summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-11-19 16:45:16 +0000
committerDavid Robillard <d@drobilla.net>2006-11-19 16:45:16 +0000
commitef6b25432d9c46d71b08c0f7d5f2686df428c4e8 (patch)
tree9b30d87b6670aadce365c9b112321dd674a0bab4 /libs
parentaf105afe6cde5b0088647cea7d5e4e3314f8478b (diff)
Merged with trunk R1141
git-svn-id: svn://localhost/ardour2/branches/midi@1142 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript13
-rw-r--r--libs/ardour/ardour/audio_diskstream.h2
-rw-r--r--libs/ardour/ardour/audio_track.h5
-rw-r--r--libs/ardour/ardour/audio_unit.h2
-rw-r--r--libs/ardour/ardour/audiofilesource.h13
-rw-r--r--libs/ardour/ardour/audioregion.h14
-rw-r--r--libs/ardour/ardour/audiosource.h2
-rw-r--r--libs/ardour/ardour/automation_event.h33
-rw-r--r--libs/ardour/ardour/configuration_vars.h1
-rw-r--r--libs/ardour/ardour/coreaudiosource.h4
-rw-r--r--libs/ardour/ardour/curve.h11
-rw-r--r--libs/ardour/ardour/destructive_filesource.h4
-rw-r--r--libs/ardour/ardour/diskstream.h6
-rw-r--r--libs/ardour/ardour/insert.h16
-rw-r--r--libs/ardour/ardour/io.h40
-rw-r--r--libs/ardour/ardour/location.h16
-rw-r--r--libs/ardour/ardour/midi_diskstream.h2
-rw-r--r--libs/ardour/ardour/midi_region.h3
-rw-r--r--libs/ardour/ardour/midi_track.h2
-rw-r--r--libs/ardour/ardour/panner.h43
-rw-r--r--libs/ardour/ardour/playlist.h17
-rw-r--r--libs/ardour/ardour/redirect.h22
-rw-r--r--libs/ardour/ardour/region.h13
-rw-r--r--libs/ardour/ardour/route.h12
-rw-r--r--libs/ardour/ardour/session.h32
-rw-r--r--libs/ardour/ardour/sndfilesource.h41
-rw-r--r--libs/ardour/ardour/source.h18
-rw-r--r--libs/ardour/ardour/state_manager.h56
-rw-r--r--libs/ardour/ardour/tempo.h27
-rw-r--r--libs/ardour/ardour/track.h9
-rw-r--r--libs/ardour/ardour/types.h6
-rw-r--r--libs/ardour/ardour/vst_plugin.h1
-rw-r--r--libs/ardour/audio_diskstream.cc89
-rw-r--r--libs/ardour/audio_playlist.cc23
-rw-r--r--libs/ardour/audio_track.cc70
-rw-r--r--libs/ardour/audioengine.cc1
-rw-r--r--libs/ardour/audiofilesource.cc107
-rw-r--r--libs/ardour/audioregion.cc122
-rw-r--r--libs/ardour/audiosource.cc25
-rw-r--r--libs/ardour/automation_event.cc389
-rw-r--r--libs/ardour/control_protocol_manager.cc22
-rw-r--r--libs/ardour/coreaudiosource.cc56
-rw-r--r--libs/ardour/curve.cc42
-rw-r--r--libs/ardour/destructive_filesource.cc19
-rw-r--r--libs/ardour/diskstream.cc16
-rw-r--r--libs/ardour/globals.cc2
-rw-r--r--libs/ardour/i18n.h2
-rw-r--r--libs/ardour/insert.cc65
-rw-r--r--libs/ardour/io.cc450
-rw-r--r--libs/ardour/location.cc87
-rw-r--r--libs/ardour/midi_diskstream.cc3
-rw-r--r--libs/ardour/midi_region.cc1
-rw-r--r--libs/ardour/midi_track.cc19
-rw-r--r--libs/ardour/panner.cc288
-rw-r--r--libs/ardour/playlist.cc38
-rw-r--r--libs/ardour/plugin_manager.cc3
-rw-r--r--libs/ardour/po/sv_SE.po2025
-rw-r--r--libs/ardour/redirect.cc300
-rw-r--r--libs/ardour/region.cc65
-rw-r--r--libs/ardour/route.cc127
-rw-r--r--libs/ardour/send.cc11
-rw-r--r--libs/ardour/session.cc101
-rw-r--r--libs/ardour/session_click.cc2
-rw-r--r--libs/ardour/session_command.cc40
-rw-r--r--libs/ardour/session_state.cc132
-rw-r--r--libs/ardour/session_transport.cc5
-rw-r--r--libs/ardour/sndfile_helpers.cc4
-rw-r--r--libs/ardour/sndfilesource.cc476
-rw-r--r--libs/ardour/source.cc24
-rw-r--r--libs/ardour/source_factory.cc9
-rw-r--r--libs/ardour/sse_functions_64bit.s5
-rw-r--r--libs/ardour/state_manager.cc91
-rw-r--r--libs/ardour/tempo.cc141
-rw-r--r--libs/ardour/track.cc16
-rw-r--r--libs/ardour/utils.cc84
-rw-r--r--libs/ardour/vst_plugin.cc10
-rw-r--r--libs/clearlooks/SConscript23
-rw-r--r--libs/clearlooks/bits.c121
-rw-r--r--libs/clearlooks/clearlooks_draw.c1293
-rw-r--r--libs/clearlooks/clearlooks_draw.h159
-rw-r--r--libs/clearlooks/clearlooks_rc_style.c392
-rw-r--r--libs/clearlooks/clearlooks_rc_style.h57
-rw-r--r--libs/clearlooks/clearlooks_style.c2657
-rw-r--r--libs/clearlooks/clearlooks_style.h108
-rw-r--r--libs/clearlooks/clearlooks_theme_main.c37
-rwxr-xr-xlibs/clearlooks/cpdll.sh2
-rw-r--r--libs/clearlooks/support.c981
-rw-r--r--libs/clearlooks/support.h110
-rw-r--r--libs/fst/SConscript8
-rw-r--r--libs/gtkmm2ext/SConscript2
-rw-r--r--libs/gtkmm2ext/barcontroller.cc1
-rw-r--r--libs/gtkmm2ext/click_box.cc17
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/click_box.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtk_ui.h2
-rw-r--r--libs/gtkmm2ext/tearoff.cc18
-rw-r--r--libs/libsndfile/SConscript2
-rw-r--r--libs/midi++2/SConscript2
-rw-r--r--libs/midi++2/midi++/factory.h5
-rw-r--r--libs/midi++2/midifactory.cc30
-rw-r--r--libs/midi++2/midimanager.cc64
-rw-r--r--libs/pbd/SConscript2
-rw-r--r--libs/pbd/controllable.cc2
-rw-r--r--libs/pbd/convert.cc41
-rw-r--r--libs/pbd/pbd/command.h5
-rw-r--r--libs/pbd/pbd/controllable.h11
-rw-r--r--libs/pbd/pbd/convert.h5
-rw-r--r--libs/pbd/pbd/crossthread.h38
-rw-r--r--libs/pbd/pbd/destructible.h16
-rw-r--r--libs/pbd/pbd/memento_command.h16
-rw-r--r--libs/pbd/pbd/rcu.h2
-rw-r--r--libs/pbd/pbd/shiva.h78
-rw-r--r--libs/pbd/pbd/statefuldestructible.h12
-rw-r--r--libs/pbd/pbd/undo.h6
-rw-r--r--libs/pbd/pbd/xml++.h3
-rw-r--r--libs/pbd/undo.cc52
-rw-r--r--libs/pbd/whitespace.cc13
-rw-r--r--libs/pbd/xml++.cc28
-rw-r--r--libs/surfaces/control_protocol/SConscript1
-rw-r--r--libs/surfaces/control_protocol/basic_ui.cc4
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.cc10
120 files changed, 10647 insertions, 1883 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 58a2bbf825..98a1b362bb 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -14,7 +14,7 @@ ardour = env.Copy()
domain = 'libardour'
-ardour.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+ardour.Append(DOMAIN = domain, MAJOR = 2, MINOR = 0, MICRO = 0)
ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
ardour.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
ardour.Append(PACKAGE = domain)
@@ -44,6 +44,7 @@ buffer_set.cc
meter.cc
amp.cc
panner.cc
+destructive_filesource.cc
audiofilesource.cc
audiofilter.cc
audioregion.cc
@@ -64,7 +65,6 @@ crossfade.cc
curve.cc
cycle_timer.cc
default_click.cc
-destructive_filesource.cc
gain.cc
gdither.cc
globals.cc
@@ -105,7 +105,6 @@ sndfile_helpers.cc
sndfilesource.cc
source.cc
source_factory.cc
-state_manager.cc
tempo.cc
utils.cc
version.cc
@@ -242,7 +241,7 @@ ardour = conf.Finish ()
ardour.Merge ([
libraries['core'],
libraries['xml'],
- libraries['sndfile'],
+ libraries['sndfile-ardour'],
libraries['raptor'],
libraries['lrdf'],
libraries['samplerate'],
@@ -260,8 +259,6 @@ if ardour['LIBLO']:
if ardour['COREAUDIO'] or ardour['AUDIOUNITS']:
ardour.Merge ([ libraries['appleutility'] ])
-ardour.VersionBuild(['version.cc', 'ardour/version.h'], 'SConscript')
-
def SharedAsmObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = 1
@@ -291,7 +288,9 @@ if env['NLS']:
env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libardour))
-
+
+env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], []))
+
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions.s', 'sse_functions_64bit.s' ] +
ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 76b76b1061..4a95e094a9 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -77,6 +77,8 @@ class AudioDiskstream : public Diskstream
}
void set_record_enabled (bool yn);
+ int set_destructive (bool yn);
+ bool can_become_destructive (bool& requires_bounce) const;
float peak_power(uint32_t n=0) {
float x = channels[n].peak_power;
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index fdf373a1cb..e87434b0fb 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -37,6 +37,9 @@ class AudioTrack : public Track
AudioTrack (Session&, const XMLNode&);
~AudioTrack ();
+ int set_mode (TrackMode m);
+ bool can_use_mode (TrackMode m, bool& bounce_required);
+
int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
nframes_t offset, int declick, bool can_record, bool rec_monitors_input);
@@ -63,6 +66,8 @@ class AudioTrack : public Track
protected:
XMLNode& state (bool full);
+
+ int _set_state (const XMLNode&, bool call_base);
private:
int set_diskstream (boost::shared_ptr<AudioDiskstream>, void *);
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index 8a51580f27..88591ab845 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -1,6 +1,6 @@
/*
Copyright (C) 2006 Paul Davis
- Written by Taybin Rutkin
+ Written by Taybin Rutkin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index af5f5cdb60..bd609a7d80 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -31,6 +31,7 @@ struct SoundFileInfo {
uint16_t channels;
int64_t length;
std::string format_name;
+ int64_t timecode;
};
class AudioFileSource : public AudioSource {
@@ -81,6 +82,8 @@ class AudioFileSource : public AudioSource {
void mark_take (string);
string take_id() const { return _take_id; }
+ bool is_embedded() const { return _is_embedded; }
+
static void set_bwf_serial_number (int);
static void set_search_path (string);
@@ -93,6 +96,9 @@ class AudioFileSource : public AudioSource {
XMLNode& get_state ();
int set_state (const XMLNode&);
+ bool destructive() const { return (_flags & Destructive); }
+ virtual bool set_destructive (bool yn) { return false; }
+
/* this should really be protected, but C++ is getting stricter
and creating slots from protected member functions is starting
to cause issues.
@@ -121,9 +127,12 @@ class AudioFileSource : public AudioSource {
string _path;
Flag _flags;
string _take_id;
- uint64_t timeline_position;
+ int64_t timeline_position;
bool file_is_new;
+ bool _is_embedded;
+ static bool determine_embeddedness(string path);
+
static string peak_dir;
static string search_path;
@@ -133,7 +142,7 @@ class AudioFileSource : public AudioSource {
static uint64_t header_position_offset;
- virtual void set_timeline_position (nframes_t pos);
+ virtual void set_timeline_position (int64_t pos);
virtual void set_header_timeline_position () = 0;
bool find (std::string path, bool must_exist, bool& is_new);
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index e14cfd0180..53c7e68b82 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -110,6 +110,7 @@ class AudioRegion : public Region
void set_fade_out (FadeShape, nframes_t);
void set_envelope_active (bool yn);
+ void set_default_envelope ();
int separate_by_channel (ARDOUR::Session&, vector<AudioRegion*>&) const;
@@ -143,7 +144,6 @@ class AudioRegion : public Region
void set_default_fades ();
void set_default_fade_in ();
void set_default_fade_out ();
- void set_default_envelope ();
void recompute_gain_at_end ();
void recompute_gain_at_start ();
@@ -157,8 +157,11 @@ class AudioRegion : public Region
void recompute_at_start ();
void recompute_at_end ();
- void envelope_changed (Change);
+ void envelope_changed ();
+ void fade_in_changed ();
+ void fade_out_changed ();
void source_offset_changed ();
+ void listen_to_my_curves ();
mutable Curve _fade_in;
FadeShape _fade_in_shape;
@@ -171,6 +174,13 @@ class AudioRegion : public Region
protected:
int set_live_state (const XMLNode&, Change&, bool send);
+
+ virtual bool verify_start (jack_nframes_t);
+ virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t);
+ virtual bool verify_start_mutable (jack_nframes_t&_start);
+ virtual bool verify_length (jack_nframes_t);
+ /*virtual void recompute_at_start () = 0;
+ virtual void recompute_at_end () = 0;*/
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index db82acf894..2ada255236 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -70,7 +70,7 @@ const nframes_t frames_per_peak = 256;
uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
- int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const;
+ virtual int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const;
int build_peaks ();
bool peaks_ready (sigc::slot<void>, sigc::connection&) const;
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index 22ab706f82..e5c194e683 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -33,7 +33,6 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
-#include <ardour/state_manager.h>
namespace ARDOUR {
@@ -54,14 +53,15 @@ struct ControlEvent {
};
- class AutomationList : public StateManager, public PBD::StatefulDestructible
+class AutomationList : public PBD::StatefulDestructible
{
public:
typedef std::list<ControlEvent*> AutomationEventList;
typedef AutomationEventList::iterator iterator;
typedef AutomationEventList::const_iterator const_iterator;
- AutomationList(double default_value, bool no_state = false);
+ AutomationList (double default_value);
+ AutomationList (const XMLNode&);
~AutomationList();
AutomationList (const AutomationList&);
@@ -85,8 +85,9 @@ struct ControlEvent {
void reposition_for_rt_add (double when);
void rt_add (double when, double value);
- iterator add (double when, double value, iterator, bool ignore_mode = false);
- void add (double when, double value, bool for_loading = false);
+ void add (double when, double value);
+ /* this should be private but old-school automation loading needs it in IO/Redirect */
+ void fast_simple_add (double when, double value);
void reset_range (double start, double end);
void erase_range (double start, double end);
@@ -151,13 +152,12 @@ struct ControlEvent {
(obj.*method)(*this);
}
- UndoAction get_memento () const;
-
- virtual void store_state (XMLNode& node) const;
- virtual void load_state (const XMLNode&);
+ sigc::signal<void> StateChanged;
- XMLNode &get_state(void);
+ XMLNode& get_state(void);
int set_state (const XMLNode &s);
+ XMLNode& state (bool full);
+ XMLNode& serialize_events ();
void set_max_xval (double);
double get_max_xval() const { return max_xval; }
@@ -188,12 +188,6 @@ struct ControlEvent {
protected:
- struct State : public ARDOUR::StateManager::State {
- AutomationEventList events;
-
- State (std::string why) : ARDOUR::StateManager::State (why) {}
- };
-
AutomationEventList events;
mutable Glib::Mutex lock;
bool _frozen;
@@ -215,7 +209,6 @@ struct ControlEvent {
double min_yval;
double max_yval;
double default_value;
- bool no_state;
iterator rt_insertion_point;
double rt_pos;
@@ -242,14 +235,12 @@ struct ControlEvent {
virtual double unlocked_eval (double where);
- Change restore_state (StateManager::State&);
- StateManager::State* state_factory (std::string why) const;
-
virtual ControlEvent* point_factory (double,double) const;
virtual ControlEvent* point_factory (const ControlEvent&) const;
-
AutomationList* cut_copy_clear (double, double, int op);
+
+ int deserialize_events (const XMLNode&);
};
} // namespace
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index fe65e9d433..8044190066 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -80,7 +80,6 @@ CONFIG_VARIABLE (std::string, click_emphasis_sound, "click-emphasis-sound", "")
CONFIG_VARIABLE (bool, auto_play, "auto-play", false)
CONFIG_VARIABLE (bool, auto_return, "auto-return", false)
CONFIG_VARIABLE (bool, auto_input, "auto-input", true)
-CONFIG_VARIABLE (bool, auto_loop, "auto-loop", false)
CONFIG_VARIABLE (bool, punch_in, "punch-in", false)
CONFIG_VARIABLE (bool, punch_out, "punch-out", false)
CONFIG_VARIABLE (bool, plugins_stop_with_transport, "plugins-stop-with-transport", false)
diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h
index 668fe61102..bd69c78e18 100644
--- a/libs/ardour/ardour/coreaudiosource.h
+++ b/libs/ardour/ardour/coreaudiosource.h
@@ -38,6 +38,8 @@ class CoreAudioSource : public AudioFileSource {
int flush_header () {return 0;};
void set_header_timeline_position () {};
+ static int get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg);
+
protected:
nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const;
nframes_t write_unlocked (Sample *dst, nframes_t cnt) { return 0; }
@@ -50,7 +52,7 @@ class CoreAudioSource : public AudioFileSource {
mutable nframes_t tmpbufsize;
mutable Glib::Mutex _tmpbuf_lock;
- void init (const string &str);
+ void init (string str);
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/curve.h b/libs/ardour/ardour/curve.h
index 87893ca260..df984b74e0 100644
--- a/libs/ardour/ardour/curve.h
+++ b/libs/ardour/ardour/curve.h
@@ -51,9 +51,10 @@ class Curve : public AutomationList
~Curve ();
Curve (const Curve& other);
Curve (const Curve& other, double start, double end);
+ Curve (const XMLNode&);
- bool rt_safe_get_vector (double x0, double x1, float *arg, size_t veclen);
- void get_vector (double x0, double x1, float *arg, size_t veclen);
+ bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen);
+ void get_vector (double x0, double x1, float *arg, int32_t veclen);
AutomationEventList::iterator closest_control_point_before (double xval);
AutomationEventList::iterator closest_control_point_after (double xval);
@@ -66,22 +67,20 @@ class Curve : public AutomationList
ControlEvent* point_factory (double,double) const;
ControlEvent* point_factory (const ControlEvent&) const;
- Change restore_state (StateManager::State&);
-
private:
AutomationList::iterator last_bound;
double unlocked_eval (double where);
double multipoint_eval (double x);
- void _get_vector (double x0, double x1, float *arg, size_t veclen);
+ void _get_vector (double x0, double x1, float *arg, int32_t veclen);
};
} // namespace ARDOUR
extern "C" {
- void curve_get_vector_from_c (void *arg, double, double, float*, size_t);
+ void curve_get_vector_from_c (void *arg, double, double, float*, int32_t);
}
#endif /* __ardour_curve_h__ */
diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h
index 1e75042ce9..2e6f5d0e57 100644
--- a/libs/ardour/ardour/destructive_filesource.h
+++ b/libs/ardour/ardour/destructive_filesource.h
@@ -48,6 +48,8 @@ class DestructiveFileSource : public SndFileSource {
static void setup_standard_crossfades (nframes_t sample_rate);
+ int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const;
+
protected:
nframes_t write_unlocked (Sample *src, nframes_t cnt);
@@ -66,7 +68,7 @@ class DestructiveFileSource : public SndFileSource {
void init ();
nframes_t crossfade (Sample* data, nframes_t cnt, int dir);
- void set_timeline_position (nframes_t);
+ void set_timeline_position (int64_t);
};
}
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 7a779b69bf..eb6d936222 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -90,7 +90,8 @@ class IO;
virtual void set_record_enabled (bool yn) = 0;
bool destructive() const { return _flags & Destructive; }
- virtual void set_destructive (bool yn);
+ virtual int set_destructive (bool yn) { return -1; }
+ virtual bool can_become_destructive (bool& requires_bounce) const { return false; }
bool hidden() const { return _flags & Hidden; }
bool recordable() const { return _flags & Recordable; }
@@ -137,6 +138,8 @@ class IO;
void handle_input_change (IOChange, void *src);
+ void remove_region_from_last_capture (boost::weak_ptr<Region> wregion);
+
sigc::signal<void> RecordEnableChanged;
sigc::signal<void> SpeedChanged;
sigc::signal<void> ReverseChanged;
@@ -223,6 +226,7 @@ class IO;
virtual bool realtime_set_speed (double, bool global_change);
std::list<boost::shared_ptr<Region> > _last_capture_regions;
+
virtual int use_pending_capture_data (XMLNode& node) = 0;
virtual void get_input_sources () = 0;
diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h
index 5d917a8c2c..217fd89885 100644
--- a/libs/ardour/ardour/insert.h
+++ b/libs/ardour/ardour/insert.h
@@ -89,15 +89,6 @@ class PortInsert : public Insert
int32_t compute_output_streams (int32_t cnt) const;
};
-struct PluginInsertState : public RedirectState
-{
- PluginInsertState (std::string why)
- : RedirectState (why) {}
- ~PluginInsertState() {}
-
- PluginState plugin_state;
-};
-
class PluginInsert : public Insert
{
public:
@@ -112,9 +103,6 @@ class PluginInsert : public Insert
XMLNode& get_state(void);
int set_state(const XMLNode&);
- StateManager::State* state_factory (std::string why) const;
- Change restore_state (StateManager::State&);
-
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
void silence (nframes_t nframes, nframes_t offset);
@@ -160,9 +148,7 @@ class PluginInsert : public Insert
nframes_t latency();
void transport_stopped (nframes_t now);
-
- protected:
- void store_state (PluginInsertState&) const;
+ void automation_snapshot (nframes_t now);
private:
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 56566149c0..f7e1993bb2 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -36,7 +36,6 @@
#include <ardour/ardour.h>
#include <ardour/utils.h>
-#include <ardour/state_manager.h>
#include <ardour/curve.h>
#include <ardour/types.h>
#include <ardour/data_type.h>
@@ -65,7 +64,7 @@ class BufferSet;
* An IO can contain ports of varying types, making routes/inserts/etc with
* varied combinations of types (eg MIDI and audio) possible.
*/
-class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager
+class IO : public PBD::StatefulDestructible
{
public:
@@ -74,7 +73,9 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager
IO (Session&, string name,
int input_min = -1, int input_max = -1,
int output_min = -1, int output_max = -1,
- DataType default_type = DataType::AUDIO);
+ DataType default_type = DataType::AUDIO);
+
+ IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~IO();
@@ -82,18 +83,12 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager
ChanCount input_maximum() const { return _input_maximum; }
ChanCount output_minimum() const { return _output_minimum; }
ChanCount output_maximum() const { return _output_maximum; }
-
+
void set_input_minimum (ChanCount n);
void set_input_maximum (ChanCount n);
void set_output_minimum (ChanCount n);
void set_output_maximum (ChanCount n);
- // Do not write any new code using these
- void set_input_minimum (int n);
- void set_input_maximum (int n);
- void set_output_minimum (int n);
- void set_output_maximum (int n);
-
DataType default_type() const { return _default_type; }
void set_default_type(DataType t) { _default_type = t; }
@@ -187,9 +182,6 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager
XMLNode& get_state (void);
int set_state (const XMLNode&);
- virtual UndoAction get_memento() const;
-
-
static int disable_connecting (void);
static int enable_connecting (void);
@@ -224,6 +216,14 @@ public:
/* automation */
+ static void set_automation_interval (jack_nframes_t frames) {
+ _automation_interval = frames;
+ }
+
+ static jack_nframes_t automation_interval() {
+ return _automation_interval;
+ }
+
void clear_automation ();
bool gain_automation_recording() const {
@@ -245,6 +245,7 @@ public:
sigc::signal<void> gain_automation_style_changed;
virtual void transport_stopped (nframes_t now);
+ void automation_snapshot (nframes_t now);
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
@@ -304,10 +305,8 @@ public:
GainControllable _gain_control;
- /* state management */
-
- Change restore_state (State&);
- StateManager::State* state_factory (std::string why) const;
+ nframes_t last_automation_snapshot;
+ static nframes_t _automation_interval;
AutoState _gain_automation_state;
AutoStyle _gain_automation_style;
@@ -315,11 +314,12 @@ public:
bool apply_gain_automation;
Curve _gain_automation_curve;
- int save_automation (const string&);
- int load_automation (const string&);
-
Glib::Mutex automation_lock;
+ virtual int set_automation_state (const XMLNode&);
+ virtual XMLNode& get_automation_state ();
+ virtual int load_automation (std::string path);
+
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_inputs (const string& str);
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index 1f1c02d67c..94f70bb4e8 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -36,7 +36,6 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
-#include <ardour/state_manager.h>
using std::string;
@@ -131,7 +130,7 @@ class Location : public PBD::StatefulDestructible
bool set_flag_internal (bool yn, Flags flag);
};
-class Locations : public StateManager, public PBD::StatefulDestructible
+class Locations : public PBD::StatefulDestructible
{
public:
typedef std::list<Location *> LocationList;
@@ -169,6 +168,7 @@ class Locations : public StateManager, public PBD::StatefulDestructible
sigc::signal<void> changed;
sigc::signal<void,Location*> added;
sigc::signal<void,Location*> removed;
+ sigc::signal<void,Change> StateChanged;
template<class T> void apply (T& obj, void (T::*method)(LocationList&)) {
Glib::Mutex::Lock lm (lock);
@@ -180,26 +180,14 @@ class Locations : public StateManager, public PBD::StatefulDestructible
(obj.*method)(locations, arg);
}
- UndoAction get_memento () const;
-
private:
- struct State : public ARDOUR::StateManager::State {
- LocationList locations;
- LocationList states;
-
- State (std::string why) : ARDOUR::StateManager::State (why) {}
- };
-
LocationList locations;
Location *current_location;
mutable Glib::Mutex lock;
int set_current_unlocked (Location *);
void location_changed (Location*);
-
- Change restore_state (StateManager::State&);
- StateManager::State* state_factory (std::string why) const;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index e62121672f..583cc23de5 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -87,7 +87,7 @@ class MidiDiskstream : public Diskstream
boost::shared_ptr<SMFSource> write_source () { return _write_source; }
- void set_destructive (bool yn); // doom!
+ int set_destructive (bool yn); // doom!
protected:
friend class Session;
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index a5c578b7cd..2fa39a37df 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -84,9 +84,6 @@ class MidiRegion : public Region
friend class Playlist;
private:
- StateManager::State* state_factory (std::string why) const;
- Change restore_state (StateManager::State&);
-
jack_nframes_t _read_at (const SourceList&, MidiRingBuffer& dst,
jack_nframes_t position,
jack_nframes_t dur,
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 6cffe01318..0347df5669 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -58,7 +58,7 @@ public:
int use_diskstream (string name);
int use_diskstream (const PBD::ID& id);
- void set_mode (TrackMode m);
+ int set_mode (TrackMode m);
void set_latency_delay (jack_nframes_t);
diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h
index 5231120840..79bff7d2a5 100644
--- a/libs/ardour/ardour/panner.h
+++ b/libs/ardour/ardour/panner.h
@@ -85,18 +85,18 @@ class StreamPanner : public sigc::trackable, public Stateful
virtual Curve& automation() = 0;
- virtual int load (istream&, string path, uint32_t&) = 0;
-
- virtual int save (ostream&) const = 0;
-
sigc::signal<void> Changed; /* for position */
sigc::signal<void> StateChanged; /* for mute */
int set_state (const XMLNode&);
virtual XMLNode& state (bool full_state) = 0;
-
+
Panner & get_parent() { return parent; }
+ /* old school automation loading */
+
+ virtual int load (istream&, string path, uint32_t&) = 0;
+
protected:
friend class Panner;
Panner& parent;
@@ -145,8 +145,6 @@ class BaseStereoPanner : public StreamPanner
void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
- int load (istream&, string path, uint32_t&);
- int save (ostream&) const;
void snapshot (nframes_t now);
void transport_stopped (nframes_t frame);
void set_automation_state (AutoState);
@@ -154,6 +152,10 @@ class BaseStereoPanner : public StreamPanner
Curve& automation() { return _automation; }
+ /* old school automation loading */
+
+ int load (istream&, string path, uint32_t&);
+
protected:
float left;
float right;
@@ -207,10 +209,7 @@ class Multi2dPanner : public StreamPanner
void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
void distribute_automated (AudioBuffer& src, BufferSet& obufs,
- nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
-
- int load (istream&, string path, uint32_t&);
- int save (ostream&) const;
+ nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
static StreamPanner* factory (Panner&);
static string name;
@@ -219,6 +218,10 @@ class Multi2dPanner : public StreamPanner
XMLNode& get_state (void);
int set_state (const XMLNode&);
+ /* old school automation loading */
+
+ int load (istream&, string path, uint32_t&);
+
private:
Curve _automation;
void update ();
@@ -244,8 +247,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
/// The fundamental Panner function
void distribute(BufferSet& src, BufferSet& dest, nframes_t start_frame, nframes_t end_frames, nframes_t nframes, nframes_t offset);
- void set_name (string);
-
bool bypassed() const { return _bypassed; }
void set_bypassed (bool yn);
@@ -265,9 +266,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
AutoStyle automation_style() const;
bool touching() const;
- int load ();
- int save () const;
-
XMLNode& get_state (void);
XMLNode& state (bool full);
int set_state (const XMLNode&);
@@ -304,12 +302,14 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
void set_position (float x, StreamPanner& orig);
void set_position (float x, float y, StreamPanner& orig);
void set_position (float x, float y, float z, StreamPanner& orig);
-
+
+ /* old school automation */
+
+ int load ();
+
private:
void distribute_no_automation(BufferSet& src, BufferSet& dest, nframes_t nframes, nframes_t offset, gain_t gain_coeff);
-
- string automation_path;
Session& _session;
uint32_t current_outs;
bool _linked;
@@ -317,6 +317,11 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
LinkDirection _link_direction;
static float current_automation_version_number;
+
+ /* old school automation handling */
+
+ std::string automation_path;
+ void set_name (std::string);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index 93b30f42ef..831c9b3905 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -63,8 +63,8 @@ class Playlist : public PBD::StatefulDestructible {
void unref();
uint32_t refcnt() const { return _refcnt; }
- const string& name() const { return _name; }
- void set_name (const string& str);
+ std::string name() const { return _name; }
+ void set_name (std::string str);
const DataType& data_type() const { return _type; }
@@ -73,6 +73,7 @@ class Playlist : public PBD::StatefulDestructible {
bool hidden() const { return _hidden; }
bool empty() const;
+ uint32_t n_regions() const;
nframes_t get_maximum_extent () const;
layer_t top_layer() const;
@@ -91,19 +92,15 @@ class Playlist : public PBD::StatefulDestructible {
void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
void nudge_after (nframes_t start, nframes_t distance, bool forwards);
- boost::shared_ptr<Region> find_region (const PBD::ID&) const;
-
Playlist* cut (list<AudioRange>&, bool result_is_hidden = true);
Playlist* copy (list<AudioRange>&, bool result_is_hidden = true);
int paste (Playlist&, nframes_t position, float times);
- uint32_t read_data_count() { return _read_data_count; }
-
- RegionList* regions_at (nframes_t frame);
- RegionList* regions_touched (nframes_t start, nframes_t end);
+ RegionList* regions_at (nframes_t frame);
+ RegionList* regions_touched (nframes_t start, nframes_t end);
+ boost::shared_ptr<Region> find_region (const PBD::ID&) const;
boost::shared_ptr<Region> top_region_at (nframes_t frame);
-
- boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir);
+ boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>));
diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h
index ae58fa9b70..79ae4516c5 100644
--- a/libs/ardour/ardour/redirect.h
+++ b/libs/ardour/ardour/redirect.h
@@ -47,14 +47,6 @@ namespace ARDOUR {
class Session;
-struct RedirectState : public StateManager::State {
- RedirectState (string why)
- : StateManager::State (why) {}
- ~RedirectState () {}
-
- bool active;
-};
-
class Redirect : public IO
{
public:
@@ -99,9 +91,6 @@ class Redirect : public IO
XMLNode& get_state (void);
int set_state (const XMLNode&);
- StateManager::State* state_factory (string why) const;
- Change restore_state (StateManager::State&);
-
void *get_gui () const { return _gui; }
void set_gui (void *p) { _gui = p; }
@@ -110,9 +99,6 @@ class Redirect : public IO
return 1.0f;
}
- int load_automation (string path);
- int save_automation (string path);
-
void what_has_automation (set<uint32_t>&) const;
void what_has_visible_automation (set<uint32_t>&) const;
const set<uint32_t>& what_can_be_automated () const { return can_automate_list; }
@@ -137,15 +123,19 @@ class Redirect : public IO
void can_automate (uint32_t);
set<uint32_t> can_automate_list;
- void store_state (RedirectState&) const;
-
virtual void automation_list_creation_callback (uint32_t, AutomationList&) {}
+ int set_automation_state (const XMLNode&);
+ XMLNode& get_automation_state ();
+
private:
bool _active;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
+
+ int old_set_automation_state (const XMLNode&);
+ int load_automation (std::string path);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 627e556cad..88bb294e5d 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -144,6 +144,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
void special_set_position (nframes_t);
void nudge_position (long, void *src);
+ bool at_natural_position () const;
void move_to_natural_position (void *src);
void trim_start (nframes_t new_position, void *src);
@@ -171,7 +172,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
void set_playlist (ARDOUR::Playlist*);
void source_deleted (boost::shared_ptr<Source>);
-
+
boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; }
uint32_t n_channels() const { return _sources.size(); }
@@ -185,7 +186,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
virtual int set_state (const XMLNode&);
virtual int set_live_state (const XMLNode&, Change&, bool send);
- boost::shared_ptr<Region> get_parent();
+ virtual boost::shared_ptr<Region> get_parent() const;
uint64_t last_layer_op() const { return _last_layer_op; }
void set_last_layer_op (uint64_t when);
@@ -214,10 +215,10 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
void maybe_uncopy ();
void first_edit ();
- bool verify_start (jack_nframes_t);
- bool verify_start_and_length (jack_nframes_t, jack_nframes_t);
- bool verify_start_mutable (jack_nframes_t&_start);
- bool verify_length (jack_nframes_t);
+ virtual bool verify_start (jack_nframes_t);
+ virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t);
+ virtual bool verify_start_mutable (jack_nframes_t&_start);
+ virtual bool verify_length (jack_nframes_t);
virtual void recompute_at_start () = 0;
virtual void recompute_at_end () = 0;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 5c71bb16d3..6bc37ee51e 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -72,8 +72,7 @@ class Route : public IO
Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max,
Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
-
- Route (Session&, const XMLNode&);
+ Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~Route();
std::string comment() { return _comment; }
@@ -205,11 +204,6 @@ class Route : public IO
sigc::signal<void,void*> SelectedChanged;
- /* undo */
-
- UndoAction get_memento() const;
- void set_state (state_id_t);
-
int set_control_outs (const vector<std::string>& ports);
IO* control_outs() { return _control_outs; }
@@ -238,6 +232,7 @@ class Route : public IO
return _mute_control;
}
+ void automation_snapshot (nframes_t now);
void protect_automation ();
void set_remote_control_id (uint32_t id);
@@ -317,13 +312,14 @@ class Route : public IO
sigc::connection input_signal_connection;
- state_id_t _current_state_id;
ChanCount redirect_max_outs;
uint32_t _remote_control_id;
uint32_t pans_required() const;
ChanCount n_process_buffers ();
+ virtual int _set_state (const XMLNode&, bool call_base);
+
private:
void init ();
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index f06c4117a6..039bf92362 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -359,7 +359,10 @@ class Session : public PBD::StatefulDestructible
void request_bounded_roll (nframes_t start, nframes_t end);
void request_stop (bool abort = false);
void request_locate (nframes_t frame, bool with_roll = false);
+
void request_play_loop (bool yn);
+ bool get_play_loop () const { return play_loop; }
+
nframes_t last_transport_start() const { return _last_roll_location; }
void goto_end () { request_locate (end_location->start(), false);}
void goto_start () { request_locate (start_location->start(), false); }
@@ -562,7 +565,8 @@ class Session : public PBD::StatefulDestructible
string new_region_name (string);
string path_from_region_name (string name, string identifier);
- boost::shared_ptr<Region> find_whole_file_parent (Region&);
+ boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>);
+
void find_equivalent_playlist_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >& result);
boost::shared_ptr<Region> XMLRegionFactory (const XMLNode&, bool full);
@@ -646,6 +650,7 @@ class Session : public PBD::StatefulDestructible
uint32_t n_playlists() const;
template<class T> void foreach_playlist (T *obj, void (T::*func)(Playlist *));
+ void get_playlists (std::vector<Playlist*>&);
/* named selections */
@@ -757,16 +762,19 @@ class Session : public PBD::StatefulDestructible
/* History (for editors, mixers, UIs etc.) */
void undo (uint32_t n) {
- history.undo (n);
+ _history.undo (n);
}
+
void redo (uint32_t n) {
- history.redo (n);
+ _history.redo (n);
}
- uint32_t undo_depth() const { return history.undo_depth(); }
- uint32_t redo_depth() const { return history.redo_depth(); }
- string next_undo() const { return history.next_undo(); }
- string next_redo() const { return history.next_redo(); }
+ UndoHistory& history() { return _history; }
+
+ uint32_t undo_depth() const { return _history.undo_depth(); }
+ uint32_t redo_depth() const { return _history.redo_depth(); }
+ string next_undo() const { return _history.next_undo(); }
+ string next_redo() const { return _history.next_redo(); }
void begin_reversible_command (string cmd_name);
void commit_reversible_command (Command* cmd = 0);
@@ -775,11 +783,11 @@ class Session : public PBD::StatefulDestructible
current_trans->add_command (cmd);
}
- std::map<PBD::ID, PBD::StatefulDestructible*> registry;
+ std::map<PBD::ID, PBD::StatefulThingWithGoingAway*> registry;
// these commands are implemented in libs/ardour/session_command.cc
Command *memento_command_factory(XMLNode *n);
- void register_with_memento_command_factory(PBD::ID, PBD::StatefulDestructible *);
+ void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway *);
class GlobalSoloStateCommand : public Command
{
@@ -944,6 +952,8 @@ class Session : public PBD::StatefulDestructible
private:
int create (bool& new_session, string* mix_template, nframes_t initial_length);
+ nframes_t compute_initial_length ();
+
static const char* _template_suffix;
static const char* _statefile_suffix;
static const char* _pending_suffix;
@@ -1566,7 +1576,7 @@ class Session : public PBD::StatefulDestructible
void reverse_diskstream_buffers ();
- UndoHistory history;
+ UndoHistory _history;
UndoTransaction* current_trans;
GlobalRouteBooleanState get_global_route_boolean (bool (Route::*method)(void) const);
@@ -1658,7 +1668,7 @@ class Session : public PBD::StatefulDestructible
void* ptr,
float opt);
- /* number of hardware audio ports we're using,
+ /* number of hardware ports we're using,
based on max (requested,available)
*/
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 50fd5e6839..1d07f6888d 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -36,10 +36,7 @@ class SndFileSource : public AudioFileSource {
/* constructor to be called for new in-session files */
SndFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate,
- Flag flags = AudioFileSource::Flag (AudioFileSource::Writable|
- AudioFileSource::Removable|
- AudioFileSource::RemovableIfEmpty|
- AudioFileSource::CanRename));
+ Flag flags = SndFileSource::default_writable_flags);
/* constructor to be called for existing in-session files */
@@ -53,6 +50,18 @@ class SndFileSource : public AudioFileSource {
nframes_t natural_position () const;
+ nframes_t last_capture_start_frame() const;
+ void mark_capture_start (nframes_t);
+ void mark_capture_end ();
+ void clear_capture_marks();
+
+ bool set_destructive (bool yn);
+
+ static void setup_standard_crossfades (nframes_t sample_rate);
+ static const AudioFileSource::Flag default_writable_flags;
+
+ static int get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg);
+
protected:
void set_header_timeline_position ();
@@ -69,10 +78,32 @@ class SndFileSource : public AudioFileSource {
mutable float *interleave_buf;
mutable nframes_t interleave_bufsize;
- void init (const string &str);
+ void init (string str);
int open();
void close();
int setup_broadcast_info (nframes_t when, struct tm&, time_t);
+
+ /* destructive */
+
+ static nframes_t xfade_frames;
+ static gain_t* out_coefficient;
+ static gain_t* in_coefficient;
+
+ bool _capture_start;
+ bool _capture_end;
+ nframes_t capture_start_frame;
+ nframes_t file_pos; // unit is frames
+ nframes_t xfade_out_count;
+ nframes_t xfade_in_count;
+ Sample* xfade_buf;
+
+ nframes_t crossfade (Sample* data, nframes_t cnt, int dir);
+ void set_timeline_position (int64_t);
+ nframes_t destructive_write_unlocked (Sample *dst, nframes_t cnt);
+ nframes_t nondestructive_write_unlocked (Sample *dst, nframes_t cnt);
+ void handle_header_position_change ();
+
+ static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index 8bf66f8b8d..e94b1af54f 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -22,6 +22,7 @@
#define __ardour_source_h__
#include <string>
+#include <set>
#include <sigc++/signal.h>
@@ -33,6 +34,7 @@
namespace ARDOUR {
class Session;
+class Playlist;
class Source : public PBD::StatefulDestructible
{
@@ -57,22 +59,34 @@ class Source : public PBD::StatefulDestructible
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () = 0;
-
+
XMLNode& get_state ();
int set_state (const XMLNode&);
+ void use () { _in_use++; }
+ void disuse () { if (_in_use) { _in_use--; } }
+
+ void add_playlist (ARDOUR::Playlist*);
+ void remove_playlist (ARDOUR::Playlist*);
+
+ uint32_t used() const;
+
+
static sigc::signal<void,Source*> SourceCreated;
protected:
void update_length (jack_nframes_t pos, jack_nframes_t cnt);
-
+
Session& _session;
string _name;
DataType _type;
time_t _timestamp;
jack_nframes_t _length;
+ std::set<ARDOUR::Playlist*> _playlists;
+
private:
+ uint32_t _in_use;
};
}
diff --git a/libs/ardour/ardour/state_manager.h b/libs/ardour/ardour/state_manager.h
deleted file mode 100644
index e123b2cb37..0000000000
--- a/libs/ardour/ardour/state_manager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __ardour_state_manager_h__
-#define __ardour_state_manager_h__
-
-#include <list>
-#include <string>
-#include <set>
-
-#include <sigc++/signal.h>
-
-#include <ardour/ardour.h>
-
-namespace ARDOUR {
-
-typedef uint32_t state_id_t;
-
-class StateManager : public virtual sigc::trackable
-{
- public:
- struct State {
- std::string operation;
- State (std::string why) : operation (why) {}
- virtual ~State() {}
- };
-
- typedef std::list<State*> StateMap;
-
- StateManager ();
- virtual ~StateManager ();
-
- virtual void drop_all_states ();
- virtual void use_state (state_id_t);
- virtual void save_state (std::string why);
-
- sigc::signal<void,Change> StateChanged;
-
- state_id_t _current_state_id;
-
- virtual bool should_save_state () const { return true; }
-
- static void prohibit_save ();
- static void allow_save (const char* why, bool dosave);
-
- protected:
- static bool _allow_save;
- static sigc::signal<void,const char*> SaveAllowed;
-
- StateMap states;
-
- virtual Change restore_state (State&) = 0;
- virtual State* state_factory (std::string why) const = 0;
- virtual void send_state_changed (Change);
-};
-
-} // namespace ARDOUR
-
-#endif /* __ardour_state_manager_h__ */
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index 7cdbe56cf2..f8751b5d2b 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -34,7 +34,6 @@
#include <sigc++/signal.h>
#include <ardour/ardour.h>
-#include <ardour/state_manager.h>
class XMLNode;
@@ -162,17 +161,7 @@ class TempoSection : public MetricSection, public Tempo {
typedef list<MetricSection*> Metrics;
-class TempoMapState : public StateManager::State {
- public:
- TempoMapState (std::string why)
- : StateManager::State (why) {
- metrics = new Metrics;
- }
-
- Metrics *metrics;
-};
-
-class TempoMap : public StateManager, public PBD::StatefulDestructible
+class TempoMap : public PBD::StatefulDestructible
{
public:
@@ -246,8 +235,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible
void dump (std::ostream&) const;
void clear ();
- UndoAction get_memento() const;
-
/* this is a helper class that we use to be able to keep
track of which meter *AND* tempo are in effect at
a given point in time.
@@ -279,6 +266,8 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible
Metric metric_at (nframes_t) const;
void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const;
+ sigc::signal<void,ARDOUR::Change> StateChanged;
+
private:
static Tempo _default_tempo;
static Meter _default_meter;
@@ -309,16 +298,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible
int move_metric_section (MetricSection&, const BBT_Time& to);
void do_insert (MetricSection* section);
-
- Change restore_state (StateManager::State&);
- StateManager::State* state_factory (std::string why) const;
-
- bool in_set_state;
-
- /* override state_manager::save_state so we can check in_set_state */
-
- void save_state (std::string why);
-
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index 243d0db46d..d7a2da2f46 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -39,6 +39,11 @@ class Track : public Route
int set_name (string str, void *src);
+ TrackMode mode () const { return _mode; }
+ virtual int set_mode (TrackMode m) { return false; }
+ virtual bool can_use_mode (TrackMode m, bool& bounce_required) { return false; }
+ sigc::signal<void> TrackModeChanged;
+
virtual int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
nframes_t offset, int declick, bool can_record, bool rec_monitors_input) = 0;
@@ -57,9 +62,6 @@ class Track : public Route
virtual int use_diskstream (string name) = 0;
virtual int use_diskstream (const PBD::ID& id) = 0;
- TrackMode mode() const { return _mode; }
- void set_mode (TrackMode m);
-
nframes_t update_total_latency();
void set_latency_delay (nframes_t);
@@ -88,7 +90,6 @@ class Track : public Route
void set_meter_point (MeterPoint, void* src);
- sigc::signal<void> ModeChanged;
sigc::signal<void> DiskstreamChanged;
sigc::signal<void> FreezeChange;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 61e5f35c95..1138b5208f 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -89,11 +89,17 @@ namespace ARDOUR {
Play = 0x4
};
+ std::string auto_state_to_string (AutoState);
+ AutoState string_to_auto_state (std::string);
+
enum AutoStyle {
Absolute = 0x1,
Trim = 0x2
};
+ std::string auto_style_to_string (AutoStyle);
+ AutoStyle string_to_auto_style (std::string);
+
enum AlignStyle {
CaptureTime,
ExistingMaterial
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index 7b8246868c..8034341bcc 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -31,7 +31,6 @@
#include <sigc++/signal.h>
#include <pbd/stateful.h>
#include <jack/types.h>
-#include <ardour/plugin_state.h>
#include <ardour/plugin.h>
using std::string;
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index f08d38a9b9..9c5f5233b7 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -383,7 +383,7 @@ AudioDiskstream::setup_destructive_playlist ()
void
AudioDiskstream::use_destructive_playlist ()
{
- /* this is called from the XML-based constructor. when its done,
+ /* this is called from the XML-based constructor or ::set_destructive. when called,
we already have a playlist and a region, but we need to
set up our sources for write. we use the sources associated
with the (presumed single, full-extent) region.
@@ -402,6 +402,10 @@ AudioDiskstream::use_destructive_playlist ()
throw failed_constructor();
}
+ /* be sure to stretch the region out to the maximum length */
+
+ region->set_length (max_frames - region->position(), this);
+
uint32_t n;
ChannelList::iterator chan;
@@ -409,6 +413,10 @@ AudioDiskstream::use_destructive_playlist ()
(*chan).write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n));
assert((*chan).write_source);
(*chan).write_source->set_allow_remove_if_empty (false);
+
+ /* this might be false if we switched modes, so force it */
+
+ (*chan).write_source->set_destructive (true);
}
/* the source list will never be reset for a destructive track */
@@ -1544,6 +1552,9 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
} else {
+ string whole_file_region_name;
+ whole_file_region_name = region_name_from_path (channels[0].write_source->name());
+
/* Register a new region with the Session that
describes the entire source. Do this first
so that any sub-regions will obviously be
@@ -1552,7 +1563,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
try {
boost::shared_ptr<Region> rx (RegionFactory::create (srcs, channels[0].write_source->last_capture_start_frame(), total_capture,
- region_name_from_path (channels[0].write_source->name()),
+ whole_file_region_name,
0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile)));
region = boost::dynamic_pointer_cast<AudioRegion> (rx);
@@ -1575,7 +1586,8 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
string region_name;
- _session.region_name (region_name, channels[0].write_source->name(), false);
+
+ _session.region_name (region_name, whole_file_region_name, false);
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
@@ -1589,9 +1601,9 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
continue; /* XXX is this OK? */
}
- _last_capture_regions.push_back (region);
+ region->GoingAway.connect (bind (mem_fun (*this, &Diskstream::remove_region_from_last_capture), boost::weak_ptr<Region>(region)));
- // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+ _last_capture_regions.push_back (region);
i_am_the_modifier++;
_playlist->add_region (region, (*ci)->start);
@@ -2234,3 +2246,70 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
return 0;
}
+
+int
+AudioDiskstream::set_destructive (bool yn)
+{
+ bool bounce_ignored;
+
+ if (yn != destructive()) {
+
+ if (yn) {
+ /* requestor should already have checked this and
+ bounced if necessary and desired
+ */
+ if (!can_become_destructive (bounce_ignored)) {
+ return -1;
+ }
+ _flags |= Destructive;
+ use_destructive_playlist ();
+ } else {
+ _flags &= ~Destructive;
+ reset_write_sources (true, true);
+ }
+ }
+
+ return 0;
+}
+
+bool
+AudioDiskstream::can_become_destructive (bool& requires_bounce) const
+{
+ if (!_playlist) {
+ requires_bounce = false;
+ return false;
+ }
+
+ /* is there only one region ? */
+
+ if (_playlist->n_regions() != 1) {
+ requires_bounce = true;
+ return false;
+ }
+
+ boost::shared_ptr<Region> first = _playlist->find_next_region (_session.current_start_frame(), Start, 1);
+ assert (first);
+
+ /* do the source(s) for the region cover the session start position ? */
+
+ if (first->position() != _session.current_start_frame()) {
+ if (first->start() > _session.current_start_frame()) {
+ requires_bounce = true;
+ return false;
+ }
+ }
+
+ /* is the source used by only 1 playlist ? */
+
+ boost::shared_ptr<AudioRegion> afirst = boost::dynamic_pointer_cast<AudioRegion> (first);
+
+ assert (afirst);
+
+ if (afirst->source()->used() > 1) {
+ requires_bounce = true;
+ return false;
+ }
+
+ requires_bounce = false;
+ return true;
+}
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index 94b80df178..335cb020ae 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -546,7 +546,7 @@ AudioPlaylist::set_state (const XMLNode& node)
}
thaw ();
- in_set_state++;
+ in_set_state--;
return 0;
}
@@ -639,12 +639,10 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
{
RegionLock rlock (this);
- RegionList::iterator i;
- RegionList::iterator tmp;
- for (i = regions.begin(); i != regions.end(); ) {
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
- tmp = i;
+ RegionList::iterator tmp = i;
++tmp;
if ((*i) == region) {
@@ -654,6 +652,21 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
i = tmp;
}
+
+ for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
+
+ set<boost::shared_ptr<Region> >::iterator xtmp = x;
+ ++xtmp;
+
+ if ((*x) == region) {
+ all_regions.erase (x);
+ changed = true;
+ }
+
+ x = xtmp;
+ }
+
+ region->set_playlist (0);
}
for (c = _crossfades.begin(); c != _crossfades.end(); ) {
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index a6cbce2c1e..f2681aceba 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -65,7 +65,7 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
: Track (sess, node)
{
- set_state (node);
+ _set_state (node, false);
}
AudioTrack::~AudioTrack ()
@@ -73,6 +73,37 @@ AudioTrack::~AudioTrack ()
}
int
+AudioTrack::set_mode (TrackMode m)
+{
+ if (m != _mode) {
+
+ if (_diskstream->set_destructive (m == Destructive)) {
+ return -1;
+ }
+
+ _mode = m;
+
+ TrackModeChanged (); /* EMIT SIGNAL */
+ }
+
+ return 0;
+}
+
+bool
+AudioTrack::can_use_mode (TrackMode m, bool& bounce_required)
+{
+ switch (m) {
+ case Normal:
+ bounce_required = false;
+ return true;
+
+ case Destructive:
+ default:
+ return _diskstream->can_become_destructive (bounce_required);
+ }
+}
+
+int
AudioTrack::deprecated_use_diskstream_connections ()
{
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
@@ -88,10 +119,10 @@ AudioTrack::deprecated_use_diskstream_connections ()
diskstream->deprecated_io_node = 0;
- set_input_minimum (-1);
- set_input_maximum (-1);
- set_output_minimum (-1);
- set_output_maximum (-1);
+ set_input_minimum (ChanCount::ZERO);
+ set_input_maximum (ChanCount::INFINITE);
+ set_output_minimum (ChanCount::ZERO);
+ set_output_maximum (ChanCount::INFINITE);
if ((prop = node.property ("gain")) != 0) {
set_gain (atof (prop->value().c_str()), this);
@@ -188,11 +219,19 @@ AudioTrack::audio_diskstream() const
int
AudioTrack::set_state (const XMLNode& node)
{
+ return _set_state (node, true);
+}
+
+int
+AudioTrack::_set_state (const XMLNode& node, bool call_base)
+{
const XMLProperty *prop;
XMLNodeConstIterator iter;
- if (Route::set_state (node)) {
- return -1;
+ if (call_base) {
+ if (Route::_set_state (node, call_base)) {
+ return -1;
+ }
}
if ((prop = node.property (X_("mode"))) != 0) {
@@ -494,6 +533,16 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
nframes_t transport_frame;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
+ {
+ Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
+ if (lm.locked()) {
+ // automation snapshot can also be called from the non-rt context
+ // and it uses the redirect list, so we take the lock out here
+ automation_snapshot (start_frame);
+ }
+ }
+
+
if (n_outputs().get_total() == 0 && _redirects.empty()) {
return 0;
}
@@ -761,7 +810,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
return;
}
- if (_session.write_one_audio_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) {
+ if (_session.write_one_audio_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) {
return;
}
@@ -780,8 +829,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state(), insert);
frii->id = insert->id();
- frii->memento = (*r)->get_memento();
-
+
_freeze_record.insert_info.push_back (frii);
/* now deactivate the insert */
@@ -802,7 +850,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
false));
new_playlist->set_orig_diskstream_id (diskstream->id());
- new_playlist->add_region (region, 0);
+ new_playlist->add_region (region, _session.current_start_frame());
new_playlist->set_frozen (true);
region->set_locked (true);
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 70541fce55..b0cd64c8d1 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <cerrno>
#include <vector>
+#include <exception>
#include <glibmm/timer.h>
#include <pbd/pthread_utils.h>
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 3078521466..16cb990ec2 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -36,7 +36,6 @@
#include <ardour/audiofilesource.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/sndfilesource.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/session.h>
#include <ardour/source_factory.h>
@@ -66,6 +65,7 @@ AudioFileSource::AudioFileSource (Session& s, string idstr, Flag flags)
: AudioSource (s, idstr), _flags (flags)
{
/* constructor used for existing external to session files. file must exist already */
+ _is_embedded = AudioFileSource::determine_embeddedness (idstr);
if (init (idstr, true)) {
throw failed_constructor ();
@@ -77,6 +77,7 @@ AudioFileSource::AudioFileSource (Session& s, std::string path, Flag flags, Samp
: AudioSource (s, path), _flags (flags)
{
/* constructor used for new internal-to-session files. file cannot exist */
+ _is_embedded = false;
if (init (path, false)) {
throw failed_constructor ();
@@ -106,6 +107,12 @@ AudioFileSource::~AudioFileSource ()
}
bool
+AudioFileSource::determine_embeddedness (std::string path)
+{
+ return (path.find("/") == 0);
+}
+
+bool
AudioFileSource::removable () const
{
return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0));
@@ -170,80 +177,16 @@ bool
AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
{
#ifdef HAVE_COREAUDIO
- OSStatus err = noErr;
- FSRef ref;
- ExtAudioFileRef af = 0;
- size_t size;
- CFStringRef name;
-
- err = FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0);
- if (err != noErr) {
- ExtAudioFileDispose (af);
- goto libsndfile;
- }
-
- err = ExtAudioFileOpen(&ref, &af);
- if (err != noErr) {
- ExtAudioFileDispose (af);
- goto libsndfile;
+ if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
+ return true;
}
-
- AudioStreamBasicDescription absd;
- memset(&absd, 0, sizeof(absd));
- size = sizeof(AudioStreamBasicDescription);
- err = ExtAudioFileGetProperty(af,
- kExtAudioFileProperty_FileDataFormat, &size, &absd);
- if (err != noErr) {
- ExtAudioFileDispose (af);
- goto libsndfile;
- }
-
- _info.samplerate = absd.mSampleRate;
- _info.channels = absd.mChannelsPerFrame;
-
- size = sizeof(_info.length);
- err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length);
- if (err != noErr) {
- ExtAudioFileDispose (af);
- goto libsndfile;
- }
-
- size = sizeof(CFStringRef);
- err = AudioFormatGetProperty(
- kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name);
- if (err != noErr) {
- ExtAudioFileDispose (af);
- goto libsndfile;
- }
-
- _info.format_name = CFStringRefToStdString(name);
-
- ExtAudioFileDispose (af);
- return true;
-
-libsndfile:
#endif // HAVE_COREAUDIO
- SNDFILE *sf;
- SF_INFO sf_info;
-
- sf_info.format = 0; // libsndfile says to clear this before sf_open().
-
- if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
- char errbuf[256];
- error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
- return false;
+ if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
+ return true;
}
- sf_close (sf);
-
- _info.samplerate = sf_info.samplerate;
- _info.channels = sf_info.channels;
- _info.length = sf_info.frames;
- _info.format_name = string_compose("Format: %1, %2",
- sndfile_major_format(sf_info.format),
- sndfile_minor_format(sf_info.format));
- return true;
+ return false;
}
XMLNode&
@@ -277,6 +220,17 @@ AudioFileSource::set_state (const XMLNode& node)
}
+ if ((prop = node.property (X_("name"))) != 0) {
+ _is_embedded = AudioFileSource::determine_embeddedness (prop->value());
+ } else {
+ _is_embedded = false;
+ }
+
+ if ((prop = node.property (X_("destructive"))) != 0) {
+ /* old style, from the period when we had DestructiveFileSource */
+ _flags = Flag (_flags | Destructive);
+ }
+
return 0;
}
@@ -318,6 +272,11 @@ AudioFileSource::mark_take (string id)
int
AudioFileSource::move_to_trash (const string trash_dir_name)
{
+ if (is_embedded()) {
+ cerr << "tried to move an embedded region to trash" << endl;
+ return -1;
+ }
+
string newpath;
if (!writable()) {
@@ -465,7 +424,11 @@ AudioFileSource::find (string pathstr, bool must_exist, bool& isnew)
/* external files and/or very very old style sessions include full paths */
_path = pathstr;
- _name = pathstr.substr (pathstr.find_last_of ('/') + 1);
+ if (is_embedded()) {
+ _name = pathstr;
+ } else {
+ _name = pathstr.substr (pathstr.find_last_of ('/') + 1);
+ }
if (access (_path.c_str(), R_OK) != 0) {
@@ -521,7 +484,7 @@ AudioFileSource::handle_header_position_change ()
}
void
-AudioFileSource::set_timeline_position (nframes_t pos)
+AudioFileSource::set_timeline_position (int64_t pos)
{
timeline_position = pos;
}
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 0f4e3807b1..939f9c02dd 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -75,7 +75,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
set_default_fades ();
set_default_envelope ();
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
}
/* Basic AudioRegion constructor (one channel) */
@@ -95,7 +95,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
set_default_fades ();
set_default_envelope ();
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
}
/* Basic AudioRegion constructor (many channels) */
@@ -110,7 +110,7 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c
set_default_fades ();
set_default_envelope ();
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
}
@@ -148,7 +148,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
_scale_amplitude = other->_scale_amplitude;
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
assert(_type == DataType::AUDIO);
}
@@ -165,7 +165,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
_fade_in_disabled = 0;
_fade_out_disabled = 0;
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
assert(_type == DataType::AUDIO);
}
@@ -187,7 +187,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
throw failed_constructor();
}
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
assert(_type == DataType::AUDIO);
}
@@ -205,16 +205,69 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
throw failed_constructor();
}
- _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ listen_to_my_curves ();
assert(_type == DataType::AUDIO);
}
AudioRegion::~AudioRegion ()
{
- cerr << "====== " << _name << " DESTRUCTOR @ " << this << endl;
- notify_callbacks ();
- GoingAway (); /* EMIT SIGNAL */
+}
+
+void
+AudioRegion::listen_to_my_curves ()
+{
+ _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+ _fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed));
+ _fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
+}
+
+bool
+AudioRegion::verify_length (nframes_t len)
+{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+ if (afs && afs->destructive()) {
+ return true;
+ } else {
+ return Region::verify_length(len);
+ }
+}
+
+bool
+AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
+{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+ if (afs && afs->destructive()) {
+ return true;
+ } else {
+ return verify_start_and_length(new_start, new_length);
+ }
+}
+
+bool
+AudioRegion::verify_start (nframes_t pos)
+{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+ if (afs && afs->destructive()) {
+ return true;
+ } else {
+ return verify_start(pos);
+ }
+}
+
+bool
+AudioRegion::verify_start_mutable (nframes_t& new_start)
+{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+ if (afs && afs->destructive()) {
+ return true;
+ } else {
+ return verify_start_mutable(new_start);
+ }
}
void
@@ -239,7 +292,7 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
if (chan_n >= _sources.size()) {
return 0;
}
-
+
if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
return 0;
} else {
@@ -450,7 +503,7 @@ AudioRegion::state (bool full)
if ((_flags & DefaultFadeIn)) {
child->add_property (X_("default"), X_("yes"));
} else {
- _fade_in.store_state (*child);
+ child->add_child_nocopy (_fade_in.get_state ());
}
child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
@@ -460,9 +513,9 @@ AudioRegion::state (bool full)
if ((_flags & DefaultFadeOut)) {
child->add_property (X_("default"), X_("yes"));
} else {
- _fade_out.store_state (*child);
+ child->add_child_nocopy (_fade_out.get_state ());
}
-
+
child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes"));
}
@@ -473,6 +526,7 @@ AudioRegion::state (bool full)
// If there are only two points, the points are in the start of the region and the end of the region
// so, if they are both at 1.0f, that means the default region.
+
if (_envelope.size() == 2 &&
_envelope.front()->value == 1.0f &&
_envelope.back()->value==1.0f) {
@@ -484,7 +538,7 @@ AudioRegion::state (bool full)
if (default_env) {
child->add_property ("default", "yes");
} else {
- _envelope.store_state (*child);
+ child->add_child_nocopy (_envelope.get_state ());
}
} else {
@@ -545,34 +599,28 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
_envelope.clear ();
- if ((prop = child->property ("default")) != 0) {
+ if ((prop = child->property ("default")) != 0 || _envelope.set_state (*child)) {
set_default_envelope ();
- } else {
- _envelope.load_state (*child);
}
_envelope.set_max_xval (_length);
_envelope.truncate_end (_length);
-
+
} else if (child->name() == "FadeIn") {
_fade_in.clear ();
- if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
+ if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in.set_state (*child)) {
set_default_fade_in ();
- } else {
- _fade_in.load_state (*child);
- }
+ }
} else if (child->name() == "FadeOut") {
_fade_out.clear ();
- if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
+ if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out.set_state (*child)) {
set_default_fade_out ();
- } else {
- _fade_out.load_state (*child);
- }
+ }
}
}
@@ -1030,7 +1078,19 @@ AudioRegion::normalize_to (float target_dB)
}
void
-AudioRegion::envelope_changed (Change ignored)
+AudioRegion::fade_in_changed ()
+{
+ send_change (FadeInChanged);
+}
+
+void
+AudioRegion::fade_out_changed ()
+{
+ send_change (FadeOutChanged);
+}
+
+void
+AudioRegion::envelope_changed ()
{
send_change (EnvelopeChanged);
}
@@ -1083,8 +1143,10 @@ AudioRegion::speed_mismatch (float sr) const
void
AudioRegion::source_offset_changed ()
{
- if (boost::dynamic_pointer_cast<DestructiveFileSource>(_sources.front())) {
- set_start (source()->natural_position(), this);
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
+
+ if (afs && afs->destructive()) {
+ // set_start (source()->natural_position(), this);
set_position (source()->natural_position(), this);
}
}
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index 419fe9240c..93165b7fe4 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -368,26 +368,29 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path)
error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
return -1;
}
- } else {
- /* we found it in the peaks dir */
- }
-
- if (statbuf.st_size == 0) {
_peaks_built = false;
+
} else {
- // Check if the audio file has changed since the peakfile was built.
- struct stat stat_file;
- int err = stat (audio_path.c_str(), &stat_file);
- if (!err && stat_file.st_mtime > statbuf.st_mtime){
+ /* we found it in the peaks dir, so check it out */
+
+ if (statbuf.st_size == 0) {
_peaks_built = false;
} else {
- _peaks_built = true;
+ // Check if the audio file has changed since the peakfile was built.
+ struct stat stat_file;
+ int err = stat (audio_path.c_str(), &stat_file);
+
+ if (!err && stat_file.st_mtime > statbuf.st_mtime){
+ _peaks_built = false;
+ } else {
+ _peaks_built = true;
+ }
}
}
}
-
+
if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
build_peaks_from_scratch ();
}
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index f286b11607..5cc2f50e38 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -22,9 +22,11 @@
#include <climits>
#include <float.h>
#include <cmath>
+#include <sstream>
#include <algorithm>
#include <sigc++/bind.h>
#include <ardour/automation_event.h>
+#include <pbd/convert.h>
#include "i18n.h"
@@ -46,14 +48,13 @@ static void dumpit (const AutomationList& al, string prefix = "")
}
#endif
-AutomationList::AutomationList (double defval, bool with_state)
+AutomationList::AutomationList (double defval)
{
_frozen = false;
changed_when_thawed = false;
_state = Off;
_style = Absolute;
_touching = false;
- no_state = with_state;
min_yval = FLT_MIN;
max_yval = FLT_MAX;
max_xval = 0; // means "no limit"
@@ -63,10 +64,6 @@ AutomationList::AutomationList (double defval, bool with_state)
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
- if (!no_state) {
- save_state (_("initial"));
- }
-
AutomationListCreated(this);
}
@@ -83,7 +80,6 @@ AutomationList::AutomationList (const AutomationList& other)
_touching = other._touching;
_dirty = false;
rt_insertion_point = events.end();
- no_state = other.no_state;
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
@@ -111,7 +107,6 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
_touching = other._touching;
_dirty = false;
rt_insertion_point = events.end();
- no_state = other.no_state;
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
@@ -128,32 +123,36 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
delete section;
mark_dirty ();
+
AutomationListCreated(this);
}
-AutomationList::~AutomationList()
+AutomationList::AutomationList (const XMLNode& node)
{
- std::set<ControlEvent*> all_events;
- AutomationList::State* asp;
+ _frozen = false;
+ changed_when_thawed = false;
+ _touching = false;
+ min_yval = FLT_MIN;
+ max_yval = FLT_MAX;
+ max_xval = 0; // means "no limit"
+ _dirty = false;
+ _state = Off;
+ _style = Absolute;
+ rt_insertion_point = events.end();
+ lookup_cache.left = -1;
+ lookup_cache.range.first = events.end();
+
+ set_state (node);
- GoingAway ();
+ AutomationListCreated(this);
+}
+AutomationList::~AutomationList()
+{
+ GoingAway ();
+
for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
- all_events.insert (*x);
- }
-
- for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
-
- if ((asp = dynamic_cast<AutomationList::State*> (*i)) != 0) {
-
- for (AutomationEventList::iterator x = asp->events.begin(); x != asp->events.end(); ++x) {
- all_events.insert (*x);
- }
- }
- }
-
- for (std::set<ControlEvent*>::iterator i = all_events.begin(); i != all_events.end(); ++i) {
- delete (*i);
+ delete (*x);
}
}
@@ -194,7 +193,7 @@ AutomationList::maybe_signal_changed ()
if (_frozen) {
changed_when_thawed = true;
} else {
- StateChanged (Change (0));
+ StateChanged ();
}
}
@@ -236,9 +235,6 @@ AutomationList::clear ()
{
Glib::Mutex::Lock lm (lock);
events.clear ();
- if (!no_state) {
- save_state (_("cleared"));
- }
mark_dirty ();
}
@@ -270,7 +266,6 @@ void AutomationList::_x_scale (double factor)
(*i)->when = floor ((*i)->when * factor);
}
- save_state ("x-scaled");
mark_dirty ();
}
@@ -370,12 +365,19 @@ AutomationList::rt_add (double when, double value)
maybe_signal_changed ();
}
+void
+AutomationList::fast_simple_add (double when, double value)
+{
+ /* to be used only for loading pre-sorted data from saved state */
+ events.insert (events.end(), point_factory (when, value));
+}
+
#undef last_rt_insertion_point
void
-AutomationList::add (double when, double value, bool for_loading)
+AutomationList::add (double when, double value)
{
- /* this is for graphical editing and loading data from storage */
+ /* this is for graphical editing */
{
Glib::Mutex::Lock lm (lock);
@@ -407,15 +409,9 @@ AutomationList::add (double when, double value, bool for_loading)
}
mark_dirty ();
-
- if (!no_state && !for_loading) {
- save_state (_("added event"));
- }
}
- if (!for_loading) {
- maybe_signal_changed ();
- }
+ maybe_signal_changed ();
}
void
@@ -425,9 +421,6 @@ AutomationList::erase (AutomationList::iterator i)
Glib::Mutex::Lock lm (lock);
events.erase (i);
reposition_for_rt_add (0);
- if (!no_state) {
- save_state (_("removed event"));
- }
mark_dirty ();
}
maybe_signal_changed ();
@@ -440,9 +433,6 @@ AutomationList::erase (AutomationList::iterator start, AutomationList::iterator
Glib::Mutex::Lock lm (lock);
events.erase (start, end);
reposition_for_rt_add (0);
- if (!no_state) {
- save_state (_("removed multiple events"));
- }
mark_dirty ();
}
maybe_signal_changed ();
@@ -471,10 +461,6 @@ AutomationList::reset_range (double start, double endt)
reset = true;
- if (!no_state) {
- save_state (_("removed range"));
- }
-
mark_dirty ();
}
}
@@ -502,9 +488,6 @@ AutomationList::erase_range (double start, double endt)
events.erase (s, e);
reposition_for_rt_add (0);
erased = true;
- if (!no_state) {
- save_state (_("removed range"));
- }
mark_dirty ();
}
@@ -532,10 +515,6 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
++start;
}
- if (!no_state) {
- save_state (_("event range adjusted"));
- }
-
mark_dirty ();
}
@@ -554,10 +533,6 @@ AutomationList::modify (iterator iter, double when, double val)
Glib::Mutex::Lock lm (lock);
(*iter)->when = when;
(*iter)->value = val;
- if (!no_state) {
- save_state (_("event adjusted"));
- }
-
mark_dirty ();
}
@@ -609,44 +584,10 @@ AutomationList::thaw ()
{
_frozen = false;
if (changed_when_thawed) {
- StateChanged(Change(0)); /* EMIT SIGNAL */
+ StateChanged(); /* EMIT SIGNAL */
}
}
-StateManager::State*
-AutomationList::state_factory (std::string why) const
-{
- State* state = new State (why);
-
- for (AutomationEventList::const_iterator x = events.begin(); x != events.end(); ++x) {
- state->events.push_back (point_factory (**x));
- }
-
- return state;
-}
-
-Change
-AutomationList::restore_state (StateManager::State& state)
-{
- {
- Glib::Mutex::Lock lm (lock);
- State* lstate = dynamic_cast<State*> (&state);
-
- events.clear ();
- for (AutomationEventList::const_iterator x = lstate->events.begin(); x != lstate->events.end(); ++x) {
- events.push_back (point_factory (**x));
- }
- }
-
- return Change (0);
-}
-
-UndoAction
-AutomationList::get_memento () const
-{
- return sigc::bind (mem_fun (*(const_cast<AutomationList*> (this)), &StateManager::use_state), _current_state_id);
-}
-
void
AutomationList::set_max_xval (double x)
{
@@ -670,10 +611,6 @@ AutomationList::truncate_end (double last_coordinate)
double last_val;
if (events.empty()) {
- fatal << _("programming error:")
- << "AutomationList::truncate_end() called on an empty list"
- << endmsg;
- /*NOTREACHED*/
return;
}
@@ -1083,9 +1020,6 @@ AutomationList::cut_copy_clear (double start, double end, int op)
if (changed) {
reposition_for_rt_add (0);
- if (!no_state) {
- save_state (_("cut/copy/clear"));
- }
}
mark_dirty ();
@@ -1115,10 +1049,6 @@ AutomationList::copy (iterator start, iterator end)
x = tmp;
}
-
- if (!no_state) {
- save_state (_("copy"));
- }
}
return nal;
@@ -1183,11 +1113,6 @@ AutomationList::paste (AutomationList& alist, double pos, float times)
}
reposition_for_rt_add (0);
-
- if (!no_state) {
- save_state (_("paste"));
- }
-
mark_dirty ();
}
@@ -1207,64 +1132,220 @@ AutomationList::point_factory (const ControlEvent& other) const
return new ControlEvent (other);
}
-void
-AutomationList::store_state (XMLNode& node) const
+XMLNode&
+AutomationList::get_state ()
{
+ return state (true);
+}
+
+XMLNode&
+AutomationList::state (bool full)
+{
+ XMLNode* root = new XMLNode (X_("AutomationList"));
+ char buf[64];
LocaleGuard lg (X_("POSIX"));
- for (const_iterator i = const_begin(); i != const_end(); ++i) {
- char buf[64];
-
- XMLNode *pointnode = new XMLNode ("point");
-
- snprintf (buf, sizeof (buf), "%" PRIu32, (nframes_t) floor ((*i)->when));
- pointnode->add_property ("x", buf);
- snprintf (buf, sizeof (buf), "%.12g", (*i)->value);
- pointnode->add_property ("y", buf);
+ root->add_property ("id", _id.to_s());
- node.add_child_nocopy (*pointnode);
+ snprintf (buf, sizeof (buf), "%.12g", default_value);
+ root->add_property ("default", buf);
+ snprintf (buf, sizeof (buf), "%.12g", min_yval);
+ root->add_property ("min_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", max_yval);
+ root->add_property ("max_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", max_xval);
+ root->add_property ("max_xval", buf);
+
+ if (full) {
+ root->add_property ("state", auto_state_to_string (_state));
+ } else {
+ /* never save anything but Off for automation state to a template */
+ root->add_property ("state", auto_state_to_string (Off));
}
+
+ root->add_property ("style", auto_style_to_string (_style));
+
+ if (!events.empty()) {
+ root->add_child_nocopy (serialize_events());
+ }
+
+ return *root;
}
-void
-AutomationList::load_state (const XMLNode& node)
+XMLNode&
+AutomationList::serialize_events ()
{
- const XMLNodeList& elist = node.children();
- XMLNodeConstIterator i;
- XMLProperty* prop;
- nframes_t x;
- double y;
+ XMLNode* node = new XMLNode (X_("events"));
+ stringstream str;
+
+ for (iterator xx = events.begin(); xx != events.end(); ++xx) {
+ str << (double) (*xx)->when;
+ str << ' ';
+ str <<(double) (*xx)->value;
+ str << '\n';
+ }
+
+ /* XML is a bit wierd */
+
+ XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
+ content_node->set_content (str.str());
+
+ node->add_child_nocopy (*content_node);
+
+ return *node;
+}
+
+int
+AutomationList::deserialize_events (const XMLNode& node)
+{
+ if (node.children().empty()) {
+ return -1;
+ }
+
+ XMLNode* content_node = node.children().front();
+ if (content_node->content().empty()) {
+ return -1;
+ }
+
+ freeze ();
clear ();
- for (i = elist.begin(); i != elist.end(); ++i) {
-
- if ((prop = (*i)->property ("x")) == 0) {
- error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
- continue;
+ stringstream str (content_node->content());
+
+ double x;
+ double y;
+ bool ok = true;
+
+ while (str) {
+ str >> x;
+ if (!str) {
+ break;
}
- x = atoi (prop->value().c_str());
-
- if ((prop = (*i)->property ("y")) == 0) {
- error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
- continue;
+ str >> y;
+ if (!str) {
+ ok = false;
+ break;
}
- y = atof (prop->value().c_str());
-
- add (x, y);
+ fast_simple_add (x, y);
+ }
+
+ if (!ok) {
+ clear ();
+ error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
+ } else {
+ mark_dirty ();
+ reposition_for_rt_add (0);
+ maybe_signal_changed ();
}
-}
-XMLNode &AutomationList::get_state ()
-{
- XMLNode *node = new XMLNode("AutomationList");
- store_state(*node);
- return *node;
+ thaw ();
+ return 0;
}
-int AutomationList::set_state(const XMLNode &s)
+int
+AutomationList::set_state (const XMLNode& node)
{
- load_state(s);
- return 0;
+ XMLNodeList nlist = node.children();
+ XMLNode* nsos;
+ XMLNodeIterator niter;
+ const XMLProperty* prop;
+
+ if (node.name() == X_("events")) {
+ /* partial state setting*/
+ return deserialize_events (node);
+ }
+
+ if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
+
+ if ((nsos = node.child (X_("AutomationList")))) {
+ /* new school in old school clothing */
+ return set_state (*nsos);
+ }
+
+ /* old school */
+
+ const XMLNodeList& elist = node.children();
+ XMLNodeConstIterator i;
+ XMLProperty* prop;
+ jack_nframes_t x;
+ double y;
+
+ clear ();
+
+ for (i = elist.begin(); i != elist.end(); ++i) {
+
+ if ((prop = (*i)->property ("x")) == 0) {
+ error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
+ continue;
+ }
+ x = atoi (prop->value().c_str());
+
+ if ((prop = (*i)->property ("y")) == 0) {
+ error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
+ continue;
+ }
+ y = atof (prop->value().c_str());
+
+ add (x, y);
+ }
+
+ return 0;
+ }
+
+ if (node.name() != X_("AutomationList") ) {
+ error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
+ return -1;
+ }
+
+ if ((prop = node.property ("id")) != 0) {
+ _id = prop->value ();
+ /* update session AL list */
+ AutomationListCreated(this);
+ }
+
+ if ((prop = node.property (X_("default"))) != 0){
+ default_value = atof (prop->value());
+ } else {
+ default_value = 0.0;
+ }
+
+ if ((prop = node.property (X_("style"))) != 0) {
+ _style = string_to_auto_style (prop->value());
+ } else {
+ _style = Absolute;
+ }
+
+ if ((prop = node.property (X_("state"))) != 0) {
+ _state = string_to_auto_state (prop->value());
+ } else {
+ _state = Off;
+ }
+
+ if ((prop = node.property (X_("min_yval"))) != 0) {
+ min_yval = atof (prop->value ());
+ } else {
+ min_yval = FLT_MIN;
+ }
+
+ if ((prop = node.property (X_("max_yval"))) != 0) {
+ max_yval = atof (prop->value ());
+ } else {
+ max_yval = FLT_MAX;
+ }
+
+ if ((prop = node.property (X_("max_xval"))) != 0) {
+ max_xval = atof (prop->value ());
+ } else {
+ max_xval = 0; // means "no limit ;
+ }
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+ if ((*niter)->name() == X_("events")) {
+ deserialize_events (*(*niter));
+ }
+ }
+
+ return 0;
}
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
index 1ff6c28ef3..a715254747 100644
--- a/libs/ardour/control_protocol_manager.cc
+++ b/libs/ardour/control_protocol_manager.cc
@@ -36,6 +36,13 @@ ControlProtocolManager::~ControlProtocolManager()
}
control_protocols.clear ();
+
+
+ for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
+ delete (*p);
+ }
+
+ control_protocol_info.clear();
}
@@ -68,6 +75,12 @@ ControlProtocolManager::drop_session ()
delete *p;
}
control_protocols.clear ();
+
+ for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
+ delete *p;
+ }
+
+ control_protocol_info.clear();
}
}
@@ -122,6 +135,15 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
if (p != control_protocols.end()) {
control_protocols.erase (p);
+ } else {
+ cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
+ }
+
+ list<ControlProtocolInfo*>::iterator p2 = find (control_protocol_info.begin(), control_protocol_info.end(), &cpi);
+ if (p2 != control_protocol_info.end()) {
+ control_protocol_info.erase (p2);
+ } else {
+ cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocol_info" << endl;
}
}
diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc
index c8cbb7a40d..3c81b18fd4 100644
--- a/libs/ardour/coreaudiosource.cc
+++ b/libs/ardour/coreaudiosource.cc
@@ -43,7 +43,7 @@ CoreAudioSource::CoreAudioSource (Session& s, const string& idstr, Flag flags)
}
void
-CoreAudioSource::init (const string& idstr)
+CoreAudioSource::init (string idstr)
{
string::size_type pos;
@@ -84,10 +84,6 @@ CoreAudioSource::init (const string& idstr)
error << string_compose ("CoreAudioSource: %1 (%2)", cax.mOperation, name()) << endmsg;
throw failed_constructor ();
}
-
- if (_build_peakfiles) {
- _need_peakfile = true;
- }
}
CoreAudioSource::~CoreAudioSource ()
@@ -189,3 +185,53 @@ CoreAudioSource::update_header (nframes_t when, struct tm&, time_t)
{
return 0;
}
+
+int
+CoreAudioSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
+{
+ FSRef ref;
+ ExtAudioFileRef af = 0;
+ size_t size;
+ CFStringRef name;
+ int ret = -1;
+
+ if (FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0) != noErr) {
+ goto out;
+ }
+
+ if (ExtAudioFileOpen(&ref, &af) != noErr) {
+ goto out;
+ }
+
+ AudioStreamBasicDescription absd;
+ memset(&absd, 0, sizeof(absd));
+ size = sizeof(AudioStreamBasicDescription);
+ if (ExtAudioFileGetProperty (af, kExtAudioFileProperty_FileDataFormat, &size, &absd) != noErr) {
+ goto out;
+ }
+
+ _info.samplerate = absd.mSampleRate;
+ _info.channels = absd.mChannelsPerFrame;
+
+ size = sizeof(_info.length);
+ if (ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length) != noErr) {
+ goto out;
+ }
+
+ size = sizeof(CFStringRef);
+ if (AudioFormatGetProperty(kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name) != noErr) {
+ goto out;
+ }
+
+ _info.format_name = CFStringRefToStdString(name);
+
+ // XXX it would be nice to find a way to get this information if it exists
+
+ _info.timecode = 0;
+ ret = 0;
+
+ out:
+ ExtAudioFileDispose (af);
+ return ret;
+
+}
diff --git a/libs/ardour/curve.cc b/libs/ardour/curve.cc
index 7d62c5bc94..8465094775 100644
--- a/libs/ardour/curve.cc
+++ b/libs/ardour/curve.cc
@@ -40,14 +40,11 @@ using namespace ARDOUR;
using namespace sigc;
using namespace PBD;
-sigc::signal<void, Curve*> Curve::CurveCreated;
-
Curve::Curve (double minv, double maxv, double canv, bool nostate)
- : AutomationList (canv, nostate)
+ : AutomationList (canv)
{
min_yval = minv;
max_yval = maxv;
- CurveCreated(this);
}
Curve::Curve (const Curve& other)
@@ -55,7 +52,6 @@ Curve::Curve (const Curve& other)
{
min_yval = other.min_yval;
max_yval = other.max_yval;
- CurveCreated(this);
}
Curve::Curve (const Curve& other, double start, double end)
@@ -63,7 +59,11 @@ Curve::Curve (const Curve& other, double start, double end)
{
min_yval = other.min_yval;
max_yval = other.max_yval;
- CurveCreated(this);
+}
+
+Curve::Curve (const XMLNode& node)
+ : AutomationList (node)
+{
}
Curve::~Curve ()
@@ -73,7 +73,7 @@ Curve::~Curve ()
void
Curve::solve ()
{
- size_t npoints;
+ uint32_t npoints;
if (!_dirty) {
return;
@@ -88,7 +88,7 @@ Curve::solve ()
double x[npoints];
double y[npoints];
- size_t i;
+ uint32_t i;
AutomationEventList::iterator xx;
for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
@@ -207,7 +207,7 @@ Curve::solve ()
}
bool
-Curve::rt_safe_get_vector (double x0, double x1, float *vec, size_t veclen)
+Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
@@ -220,19 +220,19 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, size_t veclen)
}
void
-Curve::get_vector (double x0, double x1, float *vec, size_t veclen)
+Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
{
Glib::Mutex::Lock lm (lock);
_get_vector (x0, x1, vec, veclen);
}
void
-Curve::_get_vector (double x0, double x1, float *vec, size_t veclen)
+Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
double rx, dx, lx, hx, max_x, min_x;
- size_t i;
- size_t original_veclen;
- size_t npoints;
+ int32_t i;
+ int32_t original_veclen;
+ int32_t npoints;
if ((npoints = events.size()) == 0) {
for (i = 0; i < veclen; ++i) {
@@ -263,7 +263,7 @@ Curve::_get_vector (double x0, double x1, float *vec, size_t veclen)
*/
double frac = (min_x - x0) / (x1 - x0);
- size_t subveclen = (size_t) floor (veclen * frac);
+ int32_t subveclen = (int32_t) floor (veclen * frac);
subveclen = min (subveclen, veclen);
@@ -281,7 +281,7 @@ Curve::_get_vector (double x0, double x1, float *vec, size_t veclen)
double frac = (x1 - max_x) / (x1 - x0);
- size_t subveclen = lrintf (original_veclen * frac);
+ int32_t subveclen = (int32_t) floor (original_veclen * frac);
float val;
@@ -435,18 +435,10 @@ Curve::point_factory (const ControlEvent& other) const
return new CurvePoint (other.when, other.value);
}
-Change
-Curve::restore_state (StateManager::State& state)
-{
- mark_dirty ();
- return AutomationList::restore_state (state);
-}
-
-
extern "C" {
void
-curve_get_vector_from_c (void *arg, double x0, double x1, float* vec, size_t vecsize)
+curve_get_vector_from_c (void *arg, double x0, double x1, float* vec, int32_t vecsize)
{
static_cast<Curve*>(arg)->get_vector (x0, x1, vec, vecsize);
}
diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc
index e160ffd608..fcd85bfe8f 100644
--- a/libs/ardour/destructive_filesource.cc
+++ b/libs/ardour/destructive_filesource.cc
@@ -55,8 +55,10 @@ typedef off_t off64_t;
#include <fcntl.h>
#include <pbd/error.h>
+#include <pbd/stacktrace.h>
#include <ardour/destructive_filesource.h>
#include <ardour/utils.h>
+#include <ardour/session.h>
#include "i18n.h"
@@ -289,7 +291,7 @@ DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt)
_capture_end = false;
/* move to the correct location place */
- file_pos = capture_start_frame;
+ file_pos = capture_start_frame - timeline_position;
// split cnt in half
nframes_t subcnt = cnt / 2;
@@ -343,17 +345,16 @@ DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt)
} else {
/* in the middle of recording */
-
if (write_float (data, file_pos, cnt) != cnt) {
return 0;
}
}
-
+
old_file_pos = file_pos;
update_length (file_pos, cnt);
file_pos += cnt;
-
+
if (_build_peakfiles) {
PeakBuildRecord *pbr = 0;
@@ -409,7 +410,15 @@ DestructiveFileSource::handle_header_position_change ()
}
void
-DestructiveFileSource::set_timeline_position (nframes_t pos)
+DestructiveFileSource::set_timeline_position (int64_t)
{
//destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes
}
+
+int
+DestructiveFileSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const
+{
+ // cerr << _name << " read peaks at " << start << " for " << cnt << " tpos = " << timeline_position << endl;
+ return AudioFileSource::read_peaks (peaks, npeaks, start, cnt, samples_per_unit);
+}
+
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index e9f8499981..5f6f3956cf 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -390,14 +390,14 @@ Diskstream::set_name (string str)
}
void
-Diskstream::set_destructive (bool yn)
+Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
{
- if (yn != destructive()) {
- reset_write_sources (true, true);
- if (yn) {
- _flags |= Destructive;
- } else {
- _flags &= ~Destructive;
- }
+ boost::shared_ptr<Region> region (wregion.lock());
+
+ if (!region) {
+ return;
}
+
+ _last_capture_regions.remove (region);
}
+
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 9b5bea9d3a..f92660470c 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -128,6 +128,8 @@ setup_midi (AudioEngine& engine )
}
MIDI::Manager::instance()->add_port (request);
+
+ nports++;
}
if (nports > 1) {
diff --git a/libs/ardour/i18n.h b/libs/ardour/i18n.h
index 71a3dccab8..5d68c79edd 100644
--- a/libs/ardour/i18n.h
+++ b/libs/ardour/i18n.h
@@ -2,6 +2,7 @@
#define __i18n_h__
#include <pbd/compose.h>
+#include <pbd/convert.h>
#include "gettext.h"
#include <vector>
@@ -10,5 +11,6 @@
#define _(Text) dgettext (PACKAGE,Text)
#define N_(Text) gettext_noop (Text)
#define X_(Text) Text
+#define I18N(Array) PBD::internationalize (PACKAGE, Array)
#endif // __i18n_h__
diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc
index b557017ec7..034b043763 100644
--- a/libs/ardour/insert.cc
+++ b/libs/ardour/insert.cc
@@ -85,8 +85,6 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
init ();
- save_state (_("initial state"));
-
{
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreChannels (max(input_streams(), output_streams()));
@@ -104,8 +102,6 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
set_automatable ();
- save_state (_("initial state"));
-
_plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
{
@@ -129,8 +125,6 @@ PluginInsert::PluginInsert (const PluginInsert& other)
init ();
- save_state (_("initial state"));
-
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -325,6 +319,23 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
}
void
+PluginInsert::automation_snapshot (nframes_t now)
+{
+ map<uint32_t,AutomationList*>::iterator li;
+
+ for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
+
+ AutomationList *alist = ((*li).second);
+ if (alist != 0 && alist->automation_write ()) {
+
+ float val = _plugins[0]->get_parameter ((*li).first);
+ alist->rt_add (now, val);
+ last_automation_snapshot = now;
+ }
+ }
+}
+
+void
PluginInsert::transport_stopped (nframes_t now)
{
map<uint32_t,AutomationList*>::iterator li;
@@ -785,35 +796,6 @@ PluginInsert::latency()
return _plugins[0]->latency ();
}
-void
-PluginInsert::store_state (PluginInsertState& state) const
-{
- Redirect::store_state (state);
- _plugins[0]->store_state (state.plugin_state);
-}
-
-Change
-PluginInsert::restore_state (StateManager::State& state)
-{
- PluginInsertState* pistate = dynamic_cast<PluginInsertState*> (&state);
-
- Redirect::restore_state (state);
-
- _plugins[0]->restore_state (pistate->plugin_state);
-
- return Change (0);
-}
-
-StateManager::State*
-PluginInsert::state_factory (std::string why) const
-{
- PluginInsertState* state = new PluginInsertState (why);
-
- store_state (*state);
-
- return state;
-}
-
ARDOUR::PluginType
PluginInsert::type ()
{
@@ -851,7 +833,6 @@ PortInsert::PortInsert (Session& s, Placement p)
: Insert (s, p, 1, -1, 1, -1)
{
init ();
- save_state (_("initial state"));
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -859,7 +840,6 @@ PortInsert::PortInsert (const PortInsert& other)
: Insert (other._session, other.placement(), 1, -1, 1, -1)
{
init ();
- save_state (_("initial state"));
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -1013,10 +993,10 @@ PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
to the number of input ports we need.
*/
- set_output_maximum (in);
- set_output_minimum (in);
- set_input_maximum (out);
- set_input_minimum (out);
+ set_output_maximum (ChanCount(_default_type, in));
+ set_output_minimum (ChanCount(_default_type, in));
+ set_input_maximum (ChanCount(_default_type, out));
+ set_input_minimum (ChanCount(_default_type, out));
if (in < 0) {
in = n_outputs ().get(_default_type);
@@ -1026,8 +1006,7 @@ PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
out = n_inputs ().get(_default_type);
}
- // FIXME
- return ensure_io (ChanCount(_default_type, in), ChanCount(_default_type, out), false, this);
+ return ensure_io (ChanCount(_default_type, out), ChanCount(_default_type, in), false, this);
}
int32_t
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index af5473368b..60e7ec3f42 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -60,7 +60,7 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-static float current_automation_version_number = 1.0;
+nframes_t IO::_automation_interval = 0;
const string IO::state_node_name = "IO";
bool IO::connecting_legal = false;
@@ -137,6 +137,8 @@ IO::IO (Session& s, string name,
apply_gain_automation = false;
+ last_automation_snapshot = 0;
+
_gain_automation_state = Off;
_gain_automation_style = Absolute;
@@ -149,6 +151,43 @@ IO::IO (Session& s, string name,
// Connect to our own MoreChannels signal to connect output buffers
IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
+
+ _session.add_controllable (&_gain_control);
+}
+
+IO::IO (Session& s, const XMLNode& node, DataType dt)
+ : _session (s),
+ _output_buffers(new BufferSet()),
+ _default_type (dt),
+ _gain_control (X_("gaincontrol"), *this),
+ _gain_automation_curve (0, 0, 0) // all reset in set_state()
+{
+ // FIXME: hack
+ _meter = new PeakMeter (_session);
+
+ _panner = 0;
+ deferred_state = 0;
+ no_panner_reset = false;
+ _desired_gain = 1.0;
+ _gain = 1.0;
+ _input_connection = 0;
+ _output_connection = 0;
+
+ apply_gain_automation = false;
+
+ set_state (node);
+
+ {
+ // IO::Meter is emitted from another thread so the
+ // Meter signal must be protected.
+ Glib::Mutex::Lock guard (m_meter_signal_lock);
+ m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
+ }
+
+ // Connect to our own MoreChannels signal to connect output buffers
+ IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
+
+ _session.add_controllable (&_gain_control);
}
IO::~IO ()
@@ -1234,67 +1273,21 @@ IO::state (bool full_state)
/* automation */
if (full_state) {
+
+ XMLNode* autonode = new XMLNode (X_("Automation"));
+ autonode->add_child_nocopy (get_automation_state());
+ node->add_child_nocopy (*autonode);
+
snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
} else {
/* never store anything except Off for automation state in a template */
snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
}
- node->add_property ("automation-state", buf);
- snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
- node->add_property ("automation-style", buf);
-
- /* XXX same for pan etc. */
return *node;
}
int
-IO::connecting_became_legal ()
-{
- int ret;
-
- if (pending_state_node == 0) {
- fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
- /*NOTREACHED*/
- return -1;
- }
-
- connection_legal_c.disconnect ();
-
- ret = make_connections (*pending_state_node);
-
- if (ports_legal) {
- delete pending_state_node;
- pending_state_node = 0;
- }
-
- return ret;
-}
-
-int
-IO::ports_became_legal ()
-{
- int ret;
-
- if (pending_state_node == 0) {
- fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
- /*NOTREACHED*/
- return -1;
- }
-
- port_legal_c.disconnect ();
-
- ret = create_ports (*pending_state_node);
-
- if (connecting_legal) {
- delete pending_state_node;
- pending_state_node = 0;
- }
-
- return ret;
-}
-
-int
IO::set_state (const XMLNode& node)
{
const XMLProperty* prop;
@@ -1312,7 +1305,7 @@ IO::set_state (const XMLNode& node)
if ((prop = node.property ("name")) != 0) {
_name = prop->value();
- _panner->set_name (_name);
+ /* used to set panner name with this, but no more */
}
if ((prop = node.property ("id")) != 0) {
@@ -1338,32 +1331,29 @@ IO::set_state (const XMLNode& node)
_gain = _desired_gain;
}
+ if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
+ /* old school automation handling */
+ }
+
for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
if ((*iter)->name() == "Panner") {
+ if (_panner == 0) {
+ _panner = new Panner (_name, _session);
+ }
_panner->set_state (**iter);
}
+ if ((*iter)->name() == X_("Automation")) {
+
+ set_automation_state (*(*iter)->children().front());
+ }
+
if ((*iter)->name() == X_("gaincontrol")) {
_gain_control.set_state (**iter);
- _session.add_controllable (&_gain_control);
}
}
- if ((prop = node.property ("automation-state")) != 0) {
-
- long int x;
- x = strtol (prop->value().c_str(), 0, 16);
- set_gain_automation_state (AutoState (x));
- }
-
- if ((prop = node.property ("automation-style")) != 0) {
-
- long int x;
- x = strtol (prop->value().c_str(), 0, 16);
- set_gain_automation_style (AutoStyle (x));
- }
-
if (ports_legal) {
if (create_ports (node)) {
@@ -1396,10 +1386,147 @@ IO::set_state (const XMLNode& node)
pending_state_node = new XMLNode (node);
}
+ last_automation_snapshot = 0;
+
return 0;
}
int
+IO::set_automation_state (const XMLNode& node)
+{
+ return _gain_automation_curve.set_state (node);
+}
+
+XMLNode&
+IO::get_automation_state ()
+{
+ return (_gain_automation_curve.get_state ());
+}
+
+int
+IO::load_automation (string path)
+{
+ string fullpath;
+ ifstream in;
+ char line[128];
+ uint32_t linecnt = 0;
+ float version;
+ LocaleGuard lg (X_("POSIX"));
+
+ fullpath = _session.automation_dir();
+ fullpath += path;
+
+ in.open (fullpath.c_str());
+
+ if (!in) {
+ fullpath = _session.automation_dir();
+ fullpath += _session.snap_name();
+ fullpath += '-';
+ fullpath += path;
+
+ in.open (fullpath.c_str());
+
+ if (!in) {
+ error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
+ return -1;
+ }
+ }
+
+ clear_automation ();
+
+ while (in.getline (line, sizeof(line), '\n')) {
+ char type;
+ jack_nframes_t when;
+ double value;
+
+ if (++linecnt == 1) {
+ if (memcmp (line, "version", 7) == 0) {
+ if (sscanf (line, "version %f", &version) != 1) {
+ error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
+ return -1;
+ }
+ } else {
+ error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
+ warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
+ continue;
+ }
+
+ switch (type) {
+ case 'g':
+ _gain_automation_curve.fast_simple_add (when, value);
+ break;
+
+ case 's':
+ break;
+
+ case 'm':
+ break;
+
+ case 'p':
+ /* older (pre-1.0) versions of ardour used this */
+ break;
+
+ default:
+ warning << _("dubious automation event found (and ignored)") << endmsg;
+ }
+ }
+
+ return 0;
+}
+
+int
+IO::connecting_became_legal ()
+{
+ int ret;
+
+ if (pending_state_node == 0) {
+ fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
+ /*NOTREACHED*/
+ return -1;
+ }
+
+ connection_legal_c.disconnect ();
+
+ ret = make_connections (*pending_state_node);
+
+ if (ports_legal) {
+ delete pending_state_node;
+ pending_state_node = 0;
+ }
+
+ return ret;
+}
+int
+IO::ports_became_legal ()
+{
+ int ret;
+
+ if (pending_state_node == 0) {
+ fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
+ /*NOTREACHED*/
+ return -1;
+ }
+
+ port_legal_c.disconnect ();
+
+ ret = create_ports (*pending_state_node);
+
+ if (connecting_legal) {
+ delete pending_state_node;
+ pending_state_node = 0;
+ }
+
+ return ret;
+}
+
+int
IO::create_ports (const XMLNode& node)
{
const XMLProperty* prop;
@@ -1702,42 +1829,6 @@ IO::set_name (string name, void* src)
}
void
-IO::set_input_minimum (int n)
-{
- if (n < 0)
- _input_minimum = ChanCount::ZERO;
- else
- _input_minimum = ChanCount(_default_type, n);
-}
-
-void
-IO::set_input_maximum (int n)
-{
- if (n < 0)
- _input_maximum = ChanCount::INFINITE;
- else
- _input_maximum = ChanCount(_default_type, n);
-}
-
-void
-IO::set_output_minimum (int n)
-{
- if (n < 0)
- _output_minimum = ChanCount::ZERO;
- else
- _output_minimum = ChanCount(_default_type, n);
-}
-
-void
-IO::set_output_maximum (int n)
-{
- if (n < 0)
- _output_maximum = ChanCount::INFINITE;
- else
- _output_maximum = ChanCount(_default_type, n);
-}
-
-void
IO::set_input_minimum (ChanCount n)
{
_input_minimum = n;
@@ -2046,25 +2137,6 @@ IO::GainControllable::get_value (void) const
return direct_gain_to_control (io.effective_gain());
}
-UndoAction
-IO::get_memento() const
-{
- return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
-}
-
-Change
-IO::restore_state (StateManager::State& state)
-{
- return Change (0);
-}
-
-StateManager::State*
-IO::state_factory (std::string why) const
-{
- StateManager::State* state = new StateManager::State (why);
- return state;
-}
-
void
IO::setup_peak_meters()
{
@@ -2096,118 +2168,6 @@ IO::meter ()
_meter->meter();
}
-int
-IO::save_automation (const string& path)
-{
- string fullpath;
- ofstream out;
-
- fullpath = _session.automation_dir();
- fullpath += path;
-
- out.open (fullpath.c_str());
-
- if (!out) {
- error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
- return -1;
- }
-
- out << X_("version ") << current_automation_version_number << endl;
-
- /* XXX use apply_to_points to get thread safety */
-
- for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
- out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
- }
-
- _panner->save ();
-
- return 0;
-}
-
-int
-IO::load_automation (const string& path)
-{
- string fullpath;
- ifstream in;
- char line[128];
- uint32_t linecnt = 0;
- float version;
- LocaleGuard lg (X_("POSIX"));
-
- fullpath = _session.automation_dir();
- fullpath += path;
-
- in.open (fullpath.c_str());
-
- if (!in) {
- fullpath = _session.automation_dir();
- fullpath += _session.snap_name();
- fullpath += '-';
- fullpath += path;
- in.open (fullpath.c_str());
- if (!in) {
- error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
- return -1;
- }
- }
-
- clear_automation ();
-
- while (in.getline (line, sizeof(line), '\n')) {
- char type;
- nframes_t when;
- double value;
-
- if (++linecnt == 1) {
- if (memcmp (line, "version", 7) == 0) {
- if (sscanf (line, "version %f", &version) != 1) {
- error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
- return -1;
- }
- } else {
- error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
- return -1;
- }
-
- if (version != current_automation_version_number) {
- error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
- return -1;
- }
-
- continue;
- }
-
- if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
- warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
- continue;
- }
-
- switch (type) {
- case 'g':
- _gain_automation_curve.add (when, value, true);
- break;
-
- case 's':
- break;
-
- case 'm':
- break;
-
- case 'p':
- /* older (pre-1.0) versions of ardour used this */
- break;
-
- default:
- warning << _("dubious automation event found (and ignored)") << endmsg;
- }
- }
-
- _gain_automation_curve.save_state (_("loaded from disk"));
-
- return 0;
-}
-
void
IO::clear_automation ()
{
@@ -2226,6 +2186,7 @@ IO::set_gain_automation_state (AutoState state)
if (state != _gain_automation_curve.automation_state()) {
changed = true;
+ last_automation_snapshot = 0;
_gain_automation_curve.set_automation_state (state);
if (state != Off) {
@@ -2324,16 +2285,27 @@ IO::end_pan_touch (uint32_t which)
}
void
+IO::automation_snapshot (nframes_t now)
+{
+ if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
+
+ if (gain_automation_recording()) {
+ _gain_automation_curve.rt_add (now, gain());
+ }
+
+ _panner->snapshot (now);
+
+ last_automation_snapshot = now;
+ }
+}
+
+void
IO::transport_stopped (nframes_t frame)
{
_gain_automation_curve.reposition_for_rt_add (frame);
if (_gain_automation_curve.automation_state() != Off) {
- if (gain_automation_recording()) {
- _gain_automation_curve.save_state (_("automation write/touch"));
- }
-
/* the src=0 condition is a special signal to not propagate
automation gain changes into the mix group when locating.
*/
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index 39331cfda6..e09a59d42f 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -372,27 +372,16 @@ Locations::Locations ()
{
current_location = 0;
- save_state (_("initial"));
}
Locations::~Locations ()
{
- std::set<Location*> all_locations;
-
- for (StateMap::iterator siter = states.begin(); siter != states.end(); ++siter) {
-
- State* lstate = dynamic_cast<State*> (*siter);
-
- for (LocationList::iterator liter = lstate->locations.begin(); liter != lstate->locations.end(); ++liter) {
- all_locations.insert (*liter);
- }
-
- for (LocationList::iterator siter = lstate->states.begin(); siter != lstate->states.end(); ++siter) {
- all_locations.insert (*siter);
- }
+ for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
+ LocationList::iterator tmp = i;
+ ++tmp;
+ delete *i;
+ i = tmp;
}
-
- set_delete (&all_locations);
}
int
@@ -431,22 +420,22 @@ Locations::clear ()
{
{
Glib::Mutex::Lock lm (lock);
- LocationList::iterator tmp;
+
for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
- tmp = i;
+
+ LocationList::iterator tmp = i;
++tmp;
+
if (!(*i)->is_end() && !(*i)->is_start()) {
locations.erase (i);
}
+
i = tmp;
}
- locations.clear ();
current_location = 0;
}
- save_state (_("clear"));
-
changed (); /* EMIT SIGNAL */
current_changed (0); /* EMIT SIGNAL */
}
@@ -470,8 +459,6 @@ Locations::clear_markers ()
}
}
- save_state (_("clear markers"));
-
changed (); /* EMIT SIGNAL */
}
@@ -498,8 +485,6 @@ Locations::clear_ranges ()
current_location = 0;
}
- save_state (_("clear ranges"));
-
changed (); /* EMIT SIGNAL */
current_changed (0); /* EMIT SIGNAL */
}
@@ -516,8 +501,6 @@ Locations::add (Location *loc, bool make_current)
}
}
- save_state (_("add"));
-
added (loc); /* EMIT SIGNAL */
if (make_current) {
@@ -554,9 +537,8 @@ Locations::remove (Location *loc)
}
if (was_removed) {
- save_state (_("remove"));
-
- removed (loc); /* EMIT SIGNAL */
+
+ removed (loc); /* EMIT SIGNAL */
if (was_current) {
current_changed (0); /* EMIT SIGNAL */
@@ -569,7 +551,6 @@ Locations::remove (Location *loc)
void
Locations::location_changed (Location* loc)
{
- save_state (X_("location changed"));
changed (); /* EMIT SIGNAL */
}
@@ -599,7 +580,10 @@ Locations::set_state (const XMLNode& node)
}
nlist = node.children();
-
+
+ locations.clear ();
+ current_location = 0;
+
{
Glib::Mutex::Lock lm (lock);
@@ -809,45 +793,6 @@ Locations::auto_punch_location () const
return 0;
}
-StateManager::State*
-Locations::state_factory (std::string why) const
-{
- State* state = new State (why);
-
- state->locations = locations;
-
- for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
- state->states.push_back (new Location (**i));
- }
-
- return state;
-}
-
-Change
-Locations::restore_state (StateManager::State& state)
-{
- {
- Glib::Mutex::Lock lm (lock);
- State* lstate = dynamic_cast<State*> (&state);
-
- locations = lstate->locations;
- LocationList& states = lstate->states;
- LocationList::iterator l, s;
-
- for (l = locations.begin(), s = states.begin(); s != states.end(); ++s, ++l) {
- (*l) = (*s);
- }
- }
-
- return Change (0);
-}
-
-UndoAction
-Locations::get_memento () const
-{
- return sigc::bind (mem_fun (*(const_cast<Locations*> (this)), &StateManager::use_state), _current_state_id);
-}
-
uint32_t
Locations::num_range_markers () const
{
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 8247aac217..b1ec7da965 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -295,11 +295,12 @@ MidiDiskstream::use_copy_playlist ()
/** Overloaded from parent to die horribly
*/
-void
+int
MidiDiskstream::set_destructive (bool yn)
{
assert( ! destructive());
assert( ! yn);
+ return -1;
}
void
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index 36e5e05116..d33d19ce67 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -106,7 +106,6 @@ MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
MidiRegion::~MidiRegion ()
{
- GoingAway (); /* EMIT SIGNAL */
}
jack_nframes_t
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index f6d0a22019..a18d0c20ce 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -619,14 +619,21 @@ MidiTrack::unfreeze ()
FreezeChange (); /* EMIT SIGNAL */
}
-void
+int
MidiTrack::set_mode (TrackMode m)
{
- if (_diskstream) {
- if (_mode != m) {
- _mode = m;
- _diskstream->set_destructive (m == Destructive);
- ModeChanged();
+ assert(_diskstream);
+
+ if (m != _mode) {
+
+ if (_diskstream->set_destructive (m == Destructive)) {
+ return -1;
}
+
+ _mode = m;
+
+ TrackModeChanged (); /* EMIT SIGNAL */
}
+
+ return 0;
}
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index 0f6e78f84b..ee8e100e4a 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -75,6 +75,8 @@ StreamPanner::StreamPanner (Panner& p)
{
_muted = false;
+ parent.session().add_controllable (&_control);
+
x = 0.5;
y = 0.5;
z = 0.5;
@@ -210,11 +212,6 @@ BaseStereoPanner::transport_stopped (nframes_t frame)
_automation.reposition_for_rt_add (frame);
if (_automation.automation_state() != Off) {
-
- if (_automation.automation_write()) {
- _automation.save_state (_("automation write pass"));
- }
-
set_position (_automation.eval (frame));
}
}
@@ -239,29 +236,6 @@ BaseStereoPanner::set_automation_state (AutoState state)
}
int
-BaseStereoPanner::save (ostream& out) const
-{
- LocaleGuard lg (X_("POSIX"));
-
- /* force a single format for numeric data to ease session interchange
- across national boundaries.
- */
-
- out << "begin" << endl;
-
- for (AutomationList::const_iterator i = _automation.const_begin(); i != _automation.const_end(); ++i) {
- out << '\t' << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
- if (!out) {
- error << string_compose (_("error writing pan automation file (%s)"), strerror (errno)) << endmsg;
- return -1;
- }
- }
- out << "end" << endl;
-
- return 0;
-}
-
-int
BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
{
char line[128];
@@ -270,7 +244,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
_automation.clear ();
while (in.getline (line, sizeof (line), '\n')) {
- nframes_t when;
+ jack_nframes_t when;
double value;
++linecnt;
@@ -284,13 +258,12 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
continue;
}
- _automation.add (when, value, true);
+ _automation.fast_simple_add (when, value);
}
/* now that we are done loading */
- _automation.save_state (_("loaded from disk"));
- _automation.StateChanged (Change (0));
+ _automation.StateChanged ();
return 0;
}
@@ -543,17 +516,13 @@ EqualPowerStereoPanner::state (bool full_state)
snprintf (buf, sizeof (buf), "%.12g", x);
root->add_property (X_("x"), buf);
root->add_property (X_("type"), EqualPowerStereoPanner::name);
- if (full_state) {
- snprintf (buf, sizeof (buf), "0x%x", _automation.automation_state());
- } else {
- /* never store automation states other than off in a template */
- snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
- }
- root->add_property (X_("automation-state"), buf);
- snprintf (buf, sizeof (buf), "0x%x", _automation.automation_style());
- root->add_property (X_("automation-style"), buf);
+
+ XMLNode* autonode = new XMLNode (X_("Automation"));
+ autonode->add_child_nocopy (_automation.state (full_state));
+ root->add_child_nocopy (*autonode);
StreamPanner::add_state (*root);
+
root->add_child_nocopy (_control.get_state ());
return *root;
@@ -563,7 +532,6 @@ int
EqualPowerStereoPanner::set_state (const XMLNode& node)
{
const XMLProperty* prop;
- int x;
float pos;
LocaleGuard lg (X_("POSIX"));
@@ -572,29 +540,24 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
set_position (pos, true);
}
- if ((prop = node.property (X_("automation-state")))) {
- sscanf (prop->value().c_str(), "0x%x", &x);
- _automation.set_automation_state ((AutoState) x);
-
- if (x != Off) {
- set_position (_automation.eval (parent.session().transport_frame()));
- }
- }
-
- if ((prop = node.property (X_("automation-style")))) {
- sscanf (prop->value().c_str(), "0x%x", &x);
- _automation.set_automation_style ((AutoStyle) x);
- }
-
StreamPanner::set_state (node);
for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
+
if ((*iter)->name() == X_("panner")) {
+
_control.set_state (**iter);
- parent.session().add_controllable (&_control);
+
+ } else if ((*iter)->name() == X_("Automation")) {
+
+ _automation.set_state (*((*iter)->children().front()));
+
+ if (_automation.automation_state() != Off) {
+ set_position (_automation.eval (parent.session().transport_frame()));
+ }
}
}
-
+
return 0;
}
@@ -765,12 +728,6 @@ Multi2dPanner::load (istream& in, string path, uint32_t& linecnt)
return 0;
}
-int
-Multi2dPanner::save (ostream& out) const
-{
- return 0;
-}
-
XMLNode&
Multi2dPanner::get_state (void)
{
@@ -790,6 +747,8 @@ Multi2dPanner::state (bool full_state)
root->add_property (X_("y"), buf);
root->add_property (X_("type"), Multi2dPanner::name);
+ /* XXX no meaningful automation yet */
+
return *root;
}
@@ -827,6 +786,7 @@ Panner::Panner (string name, Session& s)
: _session (s)
{
set_name (name);
+
_linked = false;
_link_direction = SameDirection;
_bypassed = false;
@@ -857,17 +817,6 @@ Panner::set_link_direction (LinkDirection ld)
}
void
-Panner::set_name (string str)
-{
- automation_path = _session.automation_dir();
- automation_path += _session.snap_name();
- automation_path += "-pan-";
- automation_path += legalize_for_path (str);
- automation_path += ".automation";
-}
-
-
-void
Panner::set_bypassed (bool yn)
{
if (yn != _bypassed) {
@@ -883,7 +832,6 @@ Panner::reset (uint32_t nouts, uint32_t npans)
uint32_t n;
bool changed = false;
-
if (nouts < 2 || (nouts == outputs.size() && npans == size())) {
return;
}
@@ -1095,102 +1043,6 @@ Panner::clear_automation ()
_session.set_dirty ();
}
-int
-Panner::save () const
-{
- ofstream out (automation_path.c_str());
-
- if (!out) {
- error << string_compose (_("cannot open pan automation file \"%1\" for saving (%2)"), automation_path, strerror (errno))
- << endmsg;
- return -1;
- }
-
- out << X_("version ") << current_automation_version_number << endl;
-
- for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) {
- if ((*i)->save (out)) {
- return -1;
- }
- }
-
- return 0;
-}
-
-int
-Panner::load ()
-{
- char line[128];
- uint32_t linecnt = 0;
- float version;
- iterator sp;
- LocaleGuard lg (X_("POSIX"));
-
- if (automation_path.length() == 0) {
- return 0;
- }
-
- if (access (automation_path.c_str(), F_OK)) {
- return 0;
- }
-
- ifstream in (automation_path.c_str());
-
- if (!in) {
- error << string_compose (_("cannot open pan automation file %1 (%2)"),
- automation_path, strerror (errno))
- << endmsg;
- return -1;
- }
-
- sp = begin();
-
- while (in.getline (line, sizeof(line), '\n')) {
-
- if (++linecnt == 1) {
- if (memcmp (line, X_("version"), 7) == 0) {
- if (sscanf (line, "version %f", &version) != 1) {
- error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg;
- return -1;
- }
- } else {
- error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"),
- automation_path, line) << endmsg;
- return -1;
- }
-
- if (version != current_automation_version_number) {
- error << string_compose(_("mismatched pan automation event file version (%1)"), version) << endmsg;
- return -1;
- }
-
- continue;
- }
-
- if (strlen (line) == 0 || line[0] == '#') {
- continue;
- }
-
- if (strcmp (line, "begin") == 0) {
-
- if (sp == end()) {
- error << string_compose (_("too many panner states found in pan automation file %1"),
- automation_path)
- << endmsg;
- return -1;
- }
-
- if ((*sp)->load (in, automation_path, linecnt)) {
- return -1;
- }
-
- ++sp;
- }
- }
-
- return 0;
-}
-
struct PanPlugins {
string name;
uint32_t nouts;
@@ -1215,10 +1067,6 @@ Panner::state (bool full)
XMLNode* root = new XMLNode (X_("Panner"));
char buf[32];
- for (iterator p = begin(); p != end(); ++p) {
- root->add_child_nocopy ((*p)->state (full));
- }
-
root->add_property (X_("linked"), (_linked ? "yes" : "no"));
snprintf (buf, sizeof (buf), "%d", _link_direction);
root->add_property (X_("link_direction"), buf);
@@ -1235,10 +1083,8 @@ Panner::state (bool full)
root->add_child_nocopy (*onode);
}
- if (full) {
- if (save () == 0) {
- root->add_property (X_("automation"), Glib::path_get_basename (automation_path));
- }
+ for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) {
+ root->add_child_nocopy ((*i)->state (full));
}
return *root;
@@ -1329,7 +1175,7 @@ Panner::set_state (const XMLNode& node)
}
}
- /* don't try to load automation if it wasn't marked as existing */
+ /* don't try to do old-school automation loading if it wasn't marked as existing */
if ((prop = node.property (X_("automation")))) {
@@ -1629,3 +1475,83 @@ Panner::distribute (BufferSet& inbufs, BufferSet& outbufs, nframes_t start_frame
}
}
+/* old school automation handling */
+
+void
+Panner::set_name (string str)
+{
+ automation_path = _session.automation_dir();
+ automation_path += _session.snap_name();
+ automation_path += "-pan-";
+ automation_path += legalize_for_path (str);
+ automation_path += ".automation";
+}
+
+int
+Panner::load ()
+{
+ char line[128];
+ uint32_t linecnt = 0;
+ float version;
+ iterator sp;
+ LocaleGuard lg (X_("POSIX"));
+
+ if (automation_path.length() == 0) {
+ return 0;
+ }
+
+ if (access (automation_path.c_str(), F_OK)) {
+ return 0;
+ }
+
+ ifstream in (automation_path.c_str());
+
+ if (!in) {
+ error << string_compose (_("cannot open pan automation file %1 (%2)"),
+ automation_path, strerror (errno))
+ << endmsg;
+ return -1;
+ }
+
+ sp = begin();
+
+ while (in.getline (line, sizeof(line), '\n')) {
+
+ if (++linecnt == 1) {
+ if (memcmp (line, X_("version"), 7) == 0) {
+ if (sscanf (line, "version %f", &version) != 1) {
+ error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg;
+ return -1;
+ }
+ } else {
+ error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"),
+ automation_path, line) << endmsg;
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (strlen (line) == 0 || line[0] == '#') {
+ continue;
+ }
+
+ if (strcmp (line, "begin") == 0) {
+
+ if (sp == end()) {
+ error << string_compose (_("too many panner states found in pan automation file %1"),
+ automation_path)
+ << endmsg;
+ return -1;
+ }
+
+ if ((*sp)->load (in, automation_path, linecnt)) {
+ return -1;
+ }
+
+ ++sp;
+ }
+ }
+
+ return 0;
+}
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index ee60a53d66..d439cf1265 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -90,10 +90,8 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
init (hide);
_name = "unnamed"; /* reset by set_state */
-
- if (set_state (node)) {
- throw failed_constructor();
- }
+
+ /* derived class calls set_state() */
}
Playlist::Playlist (const Playlist& other, string namestr, bool hide)
@@ -264,11 +262,19 @@ Playlist::Playlist (Playlist& pl)
Playlist::~Playlist ()
{
+ {
+ RegionLock rl (this);
+
+ for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
+ (*i)->set_playlist (0);
+ }
+ }
+
/* GoingAway must be emitted by derived classes */
}
void
-Playlist::set_name (const string& str)
+Playlist::set_name (string str)
{
/* in a typical situation, a playlist is being used
by one diskstream and also is referenced by the
@@ -563,8 +569,6 @@ Playlist::remove_region_internal (boost::shared_ptr<Region>region, bool delay_so
RegionList::iterator i;
nframes_t old_length = 0;
- cerr << "removing region " << region->name() << " holding = " << holding_state() << endl;
-
if (!holding_state()) {
old_length = _get_maximum_extent();
}
@@ -1140,6 +1144,7 @@ Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> wea
return;
}
+
/* this makes a virtual call to the right kind of playlist ... */
region_changed (what_changed, region);
@@ -1259,6 +1264,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
boost::shared_ptr<Region> ret;
nframes_t closest = max_frames;
+
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
nframes_t distance;
@@ -1280,7 +1286,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
switch (dir) {
case 1: /* forwards */
- if (pos > frame) {
+ if (pos >= frame) {
if ((distance = pos - frame) < closest) {
closest = distance;
ret = r;
@@ -1291,7 +1297,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
default: /* backwards */
- if (pos < frame) {
+ if (pos <= frame) {
if ((distance = frame - pos) < closest) {
closest = distance;
ret = r;
@@ -1455,13 +1461,21 @@ Playlist::state (bool full_state)
bool
Playlist::empty() const
{
+ RegionLock rlock (const_cast<Playlist *>(this), false);
return regions.empty();
}
-ARDOUR::nframes_t
+uint32_t
+Playlist::n_regions() const
+{
+ RegionLock rlock (const_cast<Playlist *>(this), false);
+ return regions.size();
+}
+
+nframes_t
Playlist::get_maximum_extent () const
{
- RegionLock rlock (const_cast<Playlist *>(this));
+ RegionLock rlock (const_cast<Playlist *>(this), false);
return _get_maximum_extent ();
}
@@ -1488,7 +1502,7 @@ Playlist::bump_name (string name, Session &session)
do {
newname = Playlist::bump_name_once (newname);
- } while (session.playlist_by_name(newname)!=NULL);
+ } while (session.playlist_by_name (newname)!=NULL);
return newname;
}
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index bdd4d0ada6..b24b2619d3 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -86,7 +86,6 @@ PluginManager::PluginManager ()
}
refresh ();
-
if (_manager == 0) {
_manager = this;
}
@@ -109,7 +108,7 @@ PluginManager::ladspa_refresh ()
_ladspa_plugin_info.clear ();
if (ladspa_path.length() == 0) {
- ladspa_path = "/usr/local/lib/ladspa:/usr/lib/ladspa";
+ ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA";
}
ladspa_discover_from_path (ladspa_path);
diff --git a/libs/ardour/po/sv_SE.po b/libs/ardour/po/sv_SE.po
new file mode 100644
index 0000000000..ddc7f108bb
--- /dev/null
+++ b/libs/ardour/po/sv_SE.po
@@ -0,0 +1,2025 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR "Paul Davis"
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ardour\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-10-03 00:39+0200\n"
+"PO-Revision-Date: 2006-10-03 01:09+GMT+1\n"
+"Last-Translator: Petter Sundlöf <petter.sundlof@findus.dhs.org>\n"
+"Language-Team: Swedish <sv@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/ardour/diskstream.cc:258
+msgid "Location \"%1\" not valid for track loop (start >= end)"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:298
+msgid "AudioDiskstream: Playlist \"%1\" isn't an audio playlist"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:349
+msgid "AudioDiskstream %1: there is no existing playlist to make a copy of!"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:924 libs/ardour/audio_diskstream.cc:935
+msgid ""
+"AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1069
+msgid "AudioDiskstream %1: cannot read %2 from playlist at frame %3"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1412 libs/ardour/audio_diskstream.cc:1429
+msgid "AudioDiskstream %1: cannot write to disk"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1473
+msgid "AudioDiskstream \"%1\": cannot flush captured data to disk!"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1563
+msgid "%1: could not create region for complete audio file"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1587
+msgid "AudioDiskstream: could not create region for captured audio!"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1643
+msgid "programmer error: %1"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1929
+msgid "AudioDiskstream: channel %1 out of range"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:1952
+msgid "%1:%2 new capture file not initialized correctly"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:2178
+msgid "%1: cannot restore pending capture source file %2"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:2200
+msgid "%1: incorrect number of pending sources listed - ignoring them all"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:2215
+msgid "%1: cannot create whole-file region from pending capture sources"
+msgstr ""
+
+#: libs/ardour/audio_diskstream.cc:2227
+msgid "%1: cannot create region from pending capture sources"
+msgstr ""
+
+#: libs/ardour/audio_library.cc:92
+msgid "channels"
+msgstr ""
+
+#: libs/ardour/audio_library.cc:93
+msgid "samplerate"
+msgstr ""
+
+#: libs/ardour/audio_library.cc:94
+msgid "resolution"
+msgstr ""
+
+#: libs/ardour/audio_library.cc:95
+msgid "format"
+msgstr ""
+
+#: libs/ardour/audio_library.cc:102
+msgid "Could not open %1. Audio Library not saved"
+msgstr ""
+
+#: libs/ardour/audio_playlist.cc:53 libs/ardour/audio_playlist.cc:63
+#: libs/ardour/audio_playlist.cc:74 libs/ardour/audio_playlist.cc:121
+#: libs/ardour/insert.cc:84 libs/ardour/insert.cc:103
+#: libs/ardour/insert.cc:128 libs/ardour/insert.cc:862
+#: libs/ardour/insert.cc:870 libs/ardour/send.cc:39 libs/ardour/send.cc:53
+#: libs/ardour/send.cc:62 libs/ardour/session_state.cc:1128
+#: libs/ardour/session_state.cc:1170
+msgid "initial state"
+msgstr ""
+
+#: libs/ardour/audio_playlist.cc:261 libs/ardour/audio_playlist.cc:743
+msgid ""
+"programming error: non-audio Region passed to remove_overlap in audio "
+"playlist"
+msgstr ""
+
+#: libs/ardour/audio_playlist.cc:388
+msgid ""
+"programming error: non-audio Region tested for overlap in audio playlist"
+msgstr ""
+
+#: libs/ardour/audio_playlist.cc:851
+msgid "xfade change"
+msgstr ""
+
+#: libs/ardour/audio_playlist.cc:874
+msgid "region modified"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:105 libs/ardour/io.cc:1696
+#: libs/ardour/io.cc:1762
+msgid "Unknown connection \"%1\" listed for input of %2"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:107 libs/ardour/io.cc:1698
+#: libs/ardour/io.cc:1764
+msgid "in 1"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:108 libs/ardour/io.cc:1699
+#: libs/ardour/io.cc:1765
+msgid "No input connections available as a replacement"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:112 libs/ardour/io.cc:1703
+#: libs/ardour/io.cc:1769
+msgid "Connection %1 was not available - \"in 1\" used instead"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:121 libs/ardour/io.cc:1778
+msgid "improper input channel list in XML node (%1)"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:162 libs/ardour/audio_track.cc:175
+msgid "AudioTrack: audio diskstream \"%1\" not known by session"
+msgstr ""
+
+#: libs/ardour/audio_track.cc:216
+msgid "programming error: AudioTrack given state without diskstream!"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:146
+msgid "cannot activate JACK client"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:421
+msgid "register input port called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:457
+msgid "register output port called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:539
+msgid "connect called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:555
+msgid "AudioEngine: cannot connect %1 (%2) to %3 (%4)"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:568 libs/ardour/audioengine.cc:597
+msgid "disconnect called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:655
+msgid "get_port_by_name() called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:699
+msgid "get_ports called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:817
+msgid "get_nth_physical called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:845
+msgid "get_port_total_latency() called with no JACK client connection"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:851
+msgid "get_port_total_latency() called before engine was started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:982
+msgid "Unable to connect to JACK server"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:985
+msgid "Could not connect to JACK server as \"%1\""
+msgstr ""
+
+#: libs/ardour/audioengine.cc:990
+msgid "JACK server started"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:1024
+msgid "cannot shutdown connection to JACK"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:1049
+msgid "failed to connect to JACK"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:1067
+msgid "could not reregister %1"
+msgstr ""
+
+#: libs/ardour/audioengine.cc:1125
+msgid "could not reconnect %1 and %2 (err = %3)"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:355 libs/ardour/session_state.cc:2575
+msgid ""
+"there are already 1000 files with names like %1; versioning discontinued"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:369 libs/ardour/session_state.cc:2589
+msgid "cannot rename audio file source from %1 to %2 (%3)"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:376 libs/ardour/session_state.cc:2604
+msgid "cannot remove peakfile %1 for %2 (%3)"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:420
+msgid "FileSource: search path not set"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:444
+msgid ""
+"FileSource: \"%1\" is ambigous when searching %2\n"
+"\t"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:450
+msgid "Filesource: cannot find required file (%1): while searching %2"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:473
+msgid "Filesource: cannot find required file (%1): %2"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:478
+msgid "Filesource: cannot check for existing file (%1): %2"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:534 libs/ardour/insert.cc:532
+#: libs/ardour/session.cc:1967 libs/ardour/sndfilesource.cc:109
+msgid "programming error: %1"
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:540
+msgid ""
+"Programming error! Ardour tried to rename a file over another file! It's "
+"safe to continue working, but please report this to the developers."
+msgstr ""
+
+#: libs/ardour/audiofilesource.cc:545
+msgid "cannot rename audio file for %1 to %2"
+msgstr ""
+
+#: libs/ardour/audiofilter.cc:47
+msgid "audiofilter: error creating name for new audio file based on %1"
+msgstr ""
+
+#: libs/ardour/audiofilter.cc:57
+msgid "audiofilter: error creating new audio file %1 (%2)"
+msgstr ""
+
+#: libs/ardour/audioregion.cc:888 libs/ardour/audioregion.cc:950
+msgid "fade in change"
+msgstr ""
+
+#: libs/ardour/audioregion.cc:1321
+#, c-format
+msgid "normalized to %.2fdB"
+msgstr ""
+
+#: libs/ardour/audioregion.cc:1339
+msgid "envelope change"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:144
+msgid "poll on peak request pipe failed (%1)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:151
+msgid "Error on peak thread request pipe"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:184
+msgid "Error reading from peak request pipe"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:216 libs/ardour/session_butler.cc:80
+#: libs/ardour/session_midi.cc:1073
+msgid "Cannot create transport request signal pipe (%1)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:221 libs/ardour/audiosource.cc:226
+msgid "UI: cannot set O_NONBLOCK on peak request pipe (%1)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:231
+msgid "AudioSource: could not create peak thread"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:326
+msgid "cannot rename peakfile for %1 from %2 to %3 (%4)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:368
+msgid "AudioSource: cannot stat peakfile \"%1\""
+msgstr ""
+
+#: libs/ardour/audiosource.cc:466
+msgid "cannot read sample data for unscaled peak computation"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:486 libs/ardour/audiosource.cc:557
+#: libs/ardour/audiosource.cc:793 libs/ardour/audiosource.cc:882
+msgid "AudioSource: cannot open peakpath \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:657
+msgid "AudioSource[%1]: peak read - cannot read %2 samples at offset %3"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:804
+msgid "%1: could not write read raw data for peak computation (%2)"
+msgstr ""
+
+#: libs/ardour/audiosource.cc:829
+msgid "%1: could not write peak file data (%2)"
+msgstr ""
+
+#: libs/ardour/auditioner.cc:118
+msgid "Auditioning of non-audio regions not yet supported"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:67 libs/ardour/location.cc:375
+#: libs/ardour/tempo.cc:226
+msgid "initial"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:240
+msgid "cleared"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:412
+msgid "added event"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:429
+msgid "removed event"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:444
+msgid "removed multiple events"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:475 libs/ardour/automation_event.cc:506
+msgid "removed range"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:536
+msgid "event range adjusted"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:558
+msgid "event adjusted"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:673 libs/ardour/automation_event.cc:778
+#: libs/ardour/panner.cc:889
+msgid "programming error:"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:1087
+msgid "cut/copy/clear"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:1120
+msgid "copy"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:1188 libs/ardour/playlist.cc:960
+msgid "paste"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:1243
+msgid ""
+"automation list: no x-coordinate stored for control point (point ignored)"
+msgstr ""
+
+#: libs/ardour/automation_event.cc:1249
+msgid ""
+"automation list: no y-coordinate stored for control point (point ignored)"
+msgstr ""
+
+#: libs/ardour/configuration.cc:87
+msgid "loading system configuration file %1"
+msgstr ""
+
+#: libs/ardour/configuration.cc:90
+msgid "Ardour: cannot read system configuration file \"%1\""
+msgstr ""
+
+#: libs/ardour/configuration.cc:97
+msgid "Ardour: system configuration file \"%1\" not loaded successfully."
+msgstr ""
+
+#: libs/ardour/configuration.cc:111
+msgid "loading user configuration file %1"
+msgstr ""
+
+#: libs/ardour/configuration.cc:114
+msgid "Ardour: cannot read configuration file \"%1\""
+msgstr ""
+
+#: libs/ardour/configuration.cc:121
+msgid "Ardour: user configuration file \"%1\" not loaded successfully."
+msgstr ""
+
+#: libs/ardour/configuration.cc:141
+msgid "Config file %1 not saved"
+msgstr ""
+
+#: libs/ardour/configuration.cc:226
+msgid "ill-formed MIDI port specification in ardour rcfile (ignored)"
+msgstr ""
+
+#: libs/ardour/connection.cc:183
+msgid "Node for Connection has no \"name\" property"
+msgstr ""
+
+#: libs/ardour/connection.cc:191
+msgid "Node for Connection has no \"connections\" property"
+msgstr ""
+
+#: libs/ardour/connection.cc:227 libs/ardour/io.cc:1838
+msgid "IO: badly formed string in XML node for inputs \"%1\""
+msgstr ""
+
+#: libs/ardour/connection.cc:232 libs/ardour/io.cc:1843
+msgid "bad input string in XML node \"%1\""
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:84
+msgid "control protocol name \"%1\" has no descriptor"
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:89
+msgid "control protocol name \"%1\" could not be initialized"
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:145
+msgid "Instantiating mandatory control protocol %1"
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:179
+msgid "Control protocol %1 not usable"
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:192
+msgid "Control surface protocol discovered: \"%1\""
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:210
+msgid "ControlProtocolManager: cannot load module \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/control_protocol_manager.cc:218
+msgid "ControlProtocolManager: module \"%1\" has no descriptor function."
+msgstr ""
+
+#: libs/ardour/crossfade.cc:120
+msgid "Crossfade: no \"in\" region in state"
+msgstr ""
+
+#: libs/ardour/crossfade.cc:127
+msgid "Crossfade: no \"in\" region %1 found in playlist %2"
+msgstr ""
+
+#: libs/ardour/crossfade.cc:137
+msgid "Crossfade: no \"out\" region in state"
+msgstr ""
+
+#: libs/ardour/crossfade.cc:144
+msgid "Crossfade: no \"out\" region %1 found in playlist %2"
+msgstr ""
+
+#: libs/ardour/crossfade.cc:491
+msgid "active changed"
+msgstr ""
+
+#: libs/ardour/crossfade.cc:740
+msgid "old-style crossfade information - no position information"
+msgstr ""
+
+#: libs/ardour/curve.cc:117 libs/ardour/globals.cc:348
+#: libs/ardour/insert.cc:454 libs/ardour/session.cc:2432
+#: libs/ardour/session.cc:2486
+msgid "programming error: "
+msgstr ""
+
+#: libs/ardour/cycle_timer.cc:37
+msgid "CycleTimer::get_mhz(): can't open /proc/cpuinfo"
+msgstr ""
+
+#: libs/ardour/cycle_timer.cc:49
+msgid "CycleTimer::get_mhz(): cannot locate cpu MHz in /proc/cpuinfo"
+msgstr ""
+
+#: libs/ardour/cycle_timer.cc:72
+msgid "cannot locate cpu MHz in /proc/cpuinfo"
+msgstr ""
+
+#: libs/ardour/destructive_filesource.cc:200
+msgid "DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"
+msgstr ""
+
+#: libs/ardour/destructive_filesource.cc:213
+#: libs/ardour/destructive_filesource.cc:258
+#: libs/ardour/destructive_filesource.cc:265
+msgid "DestructiveFileSource: \"%1\" bad write (%2)"
+msgstr ""
+
+#: libs/ardour/destructive_filesource.cc:403
+msgid ""
+"Filesource: start time is already set for existing file (%1): Cannot change "
+"start time."
+msgstr ""
+
+#: libs/ardour/globals.cc:110
+msgid "no MIDI ports specified: no MMC or MTC control possible"
+msgstr ""
+
+#: libs/ardour/globals.cc:125
+msgid "MIDI port specifications for \"%1\" are not understandable."
+msgstr ""
+
+#: libs/ardour/globals.cc:138 libs/ardour/globals.cc:142
+#: libs/ardour/globals.cc:146
+msgid "default"
+msgstr ""
+
+#: libs/ardour/globals.cc:174
+msgid "No MMC control (MIDI port \"%1\" not available)"
+msgstr ""
+
+#: libs/ardour/globals.cc:180
+msgid "No MTC support (MIDI port \"%1\" not available)"
+msgstr ""
+
+#: libs/ardour/globals.cc:185
+msgid "No MIDI parameter support (MIDI port \"%1\" not available)"
+msgstr ""
+
+#: libs/ardour/import.cc:77
+msgid "Import: cannot open input sound file \"%1\""
+msgstr ""
+
+#: libs/ardour/import.cc:82
+msgid "resampling audio"
+msgstr ""
+
+#: libs/ardour/import.cc:86
+msgid "Import: cannot open converted sound file \"%1\""
+msgstr ""
+
+#: libs/ardour/import.cc:91
+msgid "Import: error while resampling sound file \"%1\""
+msgstr ""
+
+#: libs/ardour/import.cc:145
+msgid "Session::import_audiofile: cannot open new file source for channel %1"
+msgstr ""
+
+#: libs/ardour/import.cc:163
+msgid "converting audio"
+msgstr ""
+
+#: libs/ardour/import.cc:195
+msgid "building region"
+msgstr ""
+
+#: libs/ardour/import.cc:197
+msgid "building regions"
+msgstr ""
+
+#: libs/ardour/import.cc:309
+msgid "Import/SRC: could not open input file: %1"
+msgstr ""
+
+#: libs/ardour/import.cc:317
+msgid "Import/SRC: could not open output file: %1"
+msgstr ""
+
+#: libs/ardour/import.cc:326
+msgid "Import: src_new() failed : %1"
+msgstr ""
+
+#: libs/ardour/import.cc:354
+msgid "Import: %1"
+msgstr ""
+
+#: libs/ardour/insert.cc:651 libs/ardour/insert.cc:960
+msgid "XML node describing insert is missing the `type' field"
+msgstr ""
+
+#: libs/ardour/insert.cc:660
+msgid "unknown plugin type %1 in plugin insert state"
+msgstr ""
+
+#: libs/ardour/insert.cc:672
+msgid "XML node describing insert is missing the `id' field"
+msgstr ""
+
+#: libs/ardour/insert.cc:685
+msgid ""
+"Found a reference to a plugin (\"%1\") that is unknown.\n"
+"Perhaps it was removed or moved since it was last used."
+msgstr ""
+
+#: libs/ardour/insert.cc:723 libs/ardour/insert.cc:977
+msgid "XML node describing insert is missing a Redirect node"
+msgstr ""
+
+#: libs/ardour/insert.cc:728
+msgid "XML node describing a plugin insert is missing the `%1' information"
+msgstr ""
+
+#: libs/ardour/insert.cc:752
+msgid "PluginInsert: Auto: no ladspa port number"
+msgstr ""
+
+#: libs/ardour/insert.cc:759
+msgid "PluginInsert: Auto: port id out of range"
+msgstr ""
+
+#: libs/ardour/insert.cc:775
+msgid "XML node describing a port automation is missing the `%1' information"
+msgstr ""
+
+#: libs/ardour/insert.cc:878
+msgid "PortInsert: cannot add input port"
+msgstr ""
+
+#: libs/ardour/insert.cc:883
+msgid "PortInsert: cannot add output port"
+msgstr ""
+
+#: libs/ardour/insert.cc:965
+msgid "non-port insert XML used for port plugin insert"
+msgstr ""
+
+#: libs/ardour/io.cc:603
+msgid "IO: cannot disconnect input port %1 from %2"
+msgstr ""
+
+#: libs/ardour/io.cc:671
+msgid "IO: cannot disconnect output port %1 from %2"
+msgstr ""
+
+#: libs/ardour/io.cc:822 libs/ardour/io.cc:1177 libs/ardour/io.cc:1303
+#, c-format
+msgid "%s/out"
+msgstr ""
+
+#: libs/ardour/io.cc:824 libs/ardour/io.cc:1179 libs/ardour/io.cc:1305
+#: libs/ardour/io.cc:2688
+#, c-format
+msgid "%s/out %u"
+msgstr ""
+
+#: libs/ardour/io.cc:828 libs/ardour/io.cc:1184 libs/ardour/io.cc:1309
+msgid "IO: cannot register output port %1"
+msgstr ""
+
+#: libs/ardour/io.cc:934 libs/ardour/io.cc:1037 libs/ardour/io.cc:1143
+#, c-format
+msgid "%s/in"
+msgstr ""
+
+#: libs/ardour/io.cc:936 libs/ardour/io.cc:1040 libs/ardour/io.cc:1146
+#: libs/ardour/io.cc:2658
+#, c-format
+msgid "%s/in %u"
+msgstr ""
+
+#: libs/ardour/io.cc:940 libs/ardour/io.cc:1046 libs/ardour/io.cc:1151
+msgid "IO: cannot register input port %1"
+msgstr ""
+
+#: libs/ardour/io.cc:1551
+msgid "IO::connecting_became_legal() called without a pending state node"
+msgstr ""
+
+#: libs/ardour/io.cc:1574
+msgid "IO::ports_became_legal() called without a pending state node"
+msgstr ""
+
+#: libs/ardour/io.cc:1603
+msgid "incorrect XML node \"%1\" passed to IO object"
+msgstr ""
+
+#: libs/ardour/io.cc:1719 libs/ardour/io.cc:1787
+msgid "Unknown connection \"%1\" listed for output of %2"
+msgstr ""
+
+#: libs/ardour/io.cc:1721 libs/ardour/io.cc:1789
+msgid "out 1"
+msgstr ""
+
+#: libs/ardour/io.cc:1722 libs/ardour/io.cc:1790
+msgid "No output connections available as a replacement"
+msgstr ""
+
+#: libs/ardour/io.cc:1726 libs/ardour/io.cc:1794
+msgid "Connection %1 was not available - \"out 1\" used instead"
+msgstr ""
+
+#: libs/ardour/io.cc:1740
+msgid "%1: cannot create I/O ports"
+msgstr ""
+
+#: libs/ardour/io.cc:1803
+msgid "improper output channel list in XML node (%1)"
+msgstr ""
+
+#: libs/ardour/io.cc:1888
+msgid "IO: badly formed string in XML node for outputs \"%1\""
+msgstr ""
+
+#: libs/ardour/io.cc:1893
+msgid "IO: bad output string in XML node \"%1\""
+msgstr ""
+
+#: libs/ardour/io.cc:2391
+msgid "%1: could not open automation event file \"%2\""
+msgstr ""
+
+#: libs/ardour/io.cc:2430
+msgid "%1: cannot open automation event file \"%2\" (%2)"
+msgstr ""
+
+#: libs/ardour/io.cc:2445
+msgid "badly formed version number in automation event file \"%1\""
+msgstr ""
+
+#: libs/ardour/io.cc:2449
+msgid "no version information in automation event file \"%1\""
+msgstr ""
+
+#: libs/ardour/io.cc:2454
+msgid "mismatched automation event file version (%1)"
+msgstr ""
+
+#: libs/ardour/io.cc:2462
+msgid "badly formatted automation event record at line %1 of %2 (ignored)"
+msgstr ""
+
+#: libs/ardour/io.cc:2482
+msgid "dubious automation event found (and ignored)"
+msgstr ""
+
+#: libs/ardour/io.cc:2486 libs/ardour/panner.cc:288
+#: libs/ardour/redirect.cc:148
+msgid "loaded from disk"
+msgstr ""
+
+#: libs/ardour/io.cc:2630
+msgid "automation write/touch"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:87
+msgid "LADSPA: module has no descriptor function."
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:92
+msgid "LADSPA: plugin has gone away since discovery!"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:99
+msgid "LADSPA: \"%1\" cannot be used, since it cannot do inplace processing"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:315
+msgid ""
+"illegal parameter number used with plugin \"%1\". This mayindicate a change "
+"in the plugin design, and presets may beinvalid"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:394
+msgid "Bad node sent to LadspaPlugin::set_state"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:407
+msgid "LADSPA: no ladspa port number"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:413
+msgid "LADSPA: no ladspa port data"
+msgstr ""
+
+#: libs/ardour/ladspa_plugin.cc:653
+msgid "LADSPA: cannot load module from \"%1\""
+msgstr ""
+
+#: libs/ardour/location.cc:295
+msgid "incorrect XML node passed to Location::set_state"
+msgstr ""
+
+#: libs/ardour/location.cc:300
+msgid "XML node for Location has no ID information"
+msgstr ""
+
+#: libs/ardour/location.cc:306
+msgid "XML node for Location has no name information"
+msgstr ""
+
+#: libs/ardour/location.cc:313
+msgid "XML node for Location has no start information"
+msgstr ""
+
+#: libs/ardour/location.cc:324
+msgid "XML node for Location has no end information"
+msgstr ""
+
+#: libs/ardour/location.cc:333
+msgid "XML node for Location has no flags information"
+msgstr ""
+
+#: libs/ardour/location.cc:421
+msgid "Locations: attempt to use unknown location as selected location"
+msgstr ""
+
+#: libs/ardour/location.cc:448 libs/ardour/playlist.cc:1204
+msgid "clear"
+msgstr ""
+
+#: libs/ardour/location.cc:473
+msgid "clear markers"
+msgstr ""
+
+#: libs/ardour/location.cc:501
+msgid "clear ranges"
+msgstr ""
+
+#: libs/ardour/location.cc:519
+msgid "add"
+msgstr ""
+
+#: libs/ardour/location.cc:557
+msgid "remove"
+msgstr ""
+
+#: libs/ardour/location.cc:597
+msgid "incorrect XML mode passed to Locations::set_state"
+msgstr ""
+
+#: libs/ardour/location.cc:615
+msgid "could not load location from session file - ignored"
+msgstr ""
+
+#: libs/ardour/mtc_slave.cc:196
+msgid "MTC Slave: atomic read of current time failed, sleeping!"
+msgstr ""
+
+#: libs/ardour/named_selection.cc:77
+msgid "Chunk %1 uses an unknown playlist \"%2\""
+msgstr ""
+
+#: libs/ardour/named_selection.cc:80
+msgid "Chunk %1 contains misformed playlist information"
+msgstr ""
+
+#: libs/ardour/panner.cc:211
+msgid "automation write pass"
+msgstr ""
+
+#: libs/ardour/panner.cc:251
+#, c-format
+msgid "error writing pan automation file (%s)"
+msgstr ""
+
+#: libs/ardour/panner.cc:279
+msgid ""
+"badly formatted pan automation event record at line %1 of %2 (ignored) [%3]"
+msgstr ""
+
+#: libs/ardour/panner.cc:794
+msgid "badly-formed positional data for Multi2dPanner - ignored"
+msgstr ""
+
+#: libs/ardour/panner.cc:1083
+msgid "cannot open pan automation file \"%1\" for saving (%2)"
+msgstr ""
+
+#: libs/ardour/panner.cc:1119
+msgid "cannot open pan automation file %1 (%2)"
+msgstr ""
+
+#: libs/ardour/panner.cc:1132
+msgid "badly formed version number in pan automation event file \"%1\""
+msgstr ""
+
+#: libs/ardour/panner.cc:1136
+msgid ""
+"no version information in pan automation event file \"%1\" (first line = %2)"
+msgstr ""
+
+#: libs/ardour/panner.cc:1142
+msgid "mismatched pan automation event file version (%1)"
+msgstr ""
+
+#: libs/ardour/panner.cc:1156
+msgid "too many panner states found in pan automation file %1"
+msgstr ""
+
+#: libs/ardour/panner.cc:1297
+msgid "Unknown panner plugin \"%1\" found in pan state - ignored"
+msgstr ""
+
+#: libs/ardour/panner.cc:1303
+msgid "panner plugin node has no type information!"
+msgstr ""
+
+#: libs/ardour/playlist.cc:251
+msgid "playlist const copy constructor called"
+msgstr ""
+
+#: libs/ardour/playlist.cc:257
+msgid "playlist non-const copy constructor called"
+msgstr ""
+
+#: libs/ardour/playlist.cc:498
+msgid "add region"
+msgstr ""
+
+#: libs/ardour/playlist.cc:550
+msgid "replace region"
+msgstr ""
+
+#: libs/ardour/playlist.cc:563
+msgid "remove region"
+msgstr ""
+
+#: libs/ardour/playlist.cc:635
+msgid "separate"
+msgstr ""
+
+#: libs/ardour/playlist.cc:899
+msgid "cut"
+msgstr ""
+
+#: libs/ardour/playlist.cc:989
+msgid "duplicate"
+msgstr ""
+
+#: libs/ardour/playlist.cc:1044
+msgid "split"
+msgstr ""
+
+#: libs/ardour/playlist.cc:1121
+msgid "%1: bounds changed received for region (%2)not in playlist"
+msgstr ""
+
+#: libs/ardour/playlist.cc:1377
+msgid "Playlist: cannot create region from state file"
+msgstr ""
+
+#: libs/ardour/playlist.cc:1737
+msgid "nudged"
+msgstr ""
+
+#: libs/ardour/playlist_factory.cc:40
+msgid ""
+"programming error: Playlist::copyPlaylist called with unknown Playlist type"
+msgstr ""
+
+#: libs/ardour/plugin.cc:218
+msgid "Could not locate HOME. Preset not saved."
+msgstr ""
+
+#: libs/ardour/plugin.cc:228 libs/ardour/plugin.cc:234
+msgid "Could not create %1. Preset not saved. (%2)"
+msgstr ""
+
+#: libs/ardour/plugin.cc:239
+msgid "Error saving presets file %1."
+msgstr ""
+
+#: libs/ardour/plugin_manager.cc:192
+msgid "Could not parse rdf file: %1"
+msgstr ""
+
+#: libs/ardour/plugin_manager.cc:232
+msgid "LADSPA: cannot load module \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/plugin_manager.cc:239
+msgid "LADSPA: module \"%1\" has no descriptor function."
+msgstr ""
+
+#: libs/ardour/plugin_manager.cc:295 libs/ardour/plugin_manager.cc:307
+msgid "Unknown"
+msgstr ""
+
+#: libs/ardour/plugin_manager.cc:380
+msgid ""
+"VST plugin %1 does not support processReplacing, and so cannot be used in "
+"ardour at this time"
+msgstr ""
+
+#: libs/ardour/recent_sessions.cc:44
+msgid "cannot open recent session file %1 (%2)"
+msgstr ""
+
+#: libs/ardour/redirect.cc:77
+msgid "programming error: unknown Redirect type in Redirect::Clone!\n"
+msgstr ""
+
+#: libs/ardour/redirect.cc:102 libs/ardour/utils.cc:194
+msgid "pre"
+msgstr ""
+
+#: libs/ardour/redirect.cc:104 libs/ardour/utils.cc:197
+msgid "post"
+msgstr ""
+
+#: libs/ardour/redirect.cc:107
+msgid "Redirect: unknown placement string \"%1\" (ignored)"
+msgstr ""
+
+#: libs/ardour/redirect.cc:125
+msgid "%1: cannot open %2 to load automation data (%3)"
+msgstr ""
+
+#: libs/ardour/redirect.cc:154
+msgid "%1: cannot load automation data from %2"
+msgstr ""
+
+#: libs/ardour/redirect.cc:175
+msgid "%1: cannot open %2 to store automation data (%3)"
+msgstr ""
+
+#: libs/ardour/redirect.cc:194 libs/ardour/redirect.cc:201
+msgid "%1: could not save automation state to %2"
+msgstr ""
+
+#: libs/ardour/redirect.cc:246
+msgid "Could not get state from Redirect (%1). Problem with save_automation"
+msgstr ""
+
+#: libs/ardour/redirect.cc:296
+msgid "incorrect XML node \"%1\" passed to Redirect object"
+msgstr ""
+
+#: libs/ardour/redirect.cc:318
+msgid "%1: Automation node has no path property"
+msgstr ""
+
+#: libs/ardour/redirect.cc:343
+msgid "XML node describing an IO is missing an IO node"
+msgstr ""
+
+#: libs/ardour/redirect.cc:348
+msgid "XML node describing a redirect is missing the `active' field"
+msgstr ""
+
+#: libs/ardour/redirect.cc:358
+msgid "XML node describing a redirect is missing the `placement' field"
+msgstr ""
+
+#: libs/ardour/redirect.cc:467
+msgid "active_changed"
+msgstr ""
+
+#: libs/ardour/region.cc:901
+msgid "Session: XMLNode describing a Region is incomplete (no id)"
+msgstr ""
+
+#: libs/ardour/region.cc:908
+msgid "Session: XMLNode describing a Region is incomplete (no name)"
+msgstr ""
+
+#: libs/ardour/region_factory.cc:53 libs/ardour/region_factory.cc:70
+msgid ""
+"programming error: RegionFactory::create() called with unknown Region type"
+msgstr ""
+
+#: libs/ardour/route.cc:81 libs/ardour/session.cc:1434
+#: libs/ardour/session.cc:1440 libs/ardour/session.cc:3064
+msgid "signal"
+msgstr ""
+
+#: libs/ardour/route.cc:1407
+msgid "Could not get state of route. Problem with save_automation"
+msgstr ""
+
+#: libs/ardour/route.cc:1459
+msgid "Send construction failed"
+msgstr ""
+
+#: libs/ardour/route.cc:1481
+msgid "unknown Insert type \"%1\"; ignored"
+msgstr ""
+
+#: libs/ardour/route.cc:1487
+msgid "Insert XML node has no type property"
+msgstr ""
+
+#: libs/ardour/route.cc:1492
+msgid "insert could not be created. Ignored."
+msgstr ""
+
+#: libs/ardour/route.cc:1508
+msgid "Bad node sent to Route::set_state() [%1]"
+msgstr ""
+
+#: libs/ardour/route.cc:1572
+msgid "Route %1: unknown edit group \"%2 in saved state (ignored)"
+msgstr ""
+
+#: libs/ardour/route.cc:1588 libs/ardour/route.cc:1592
+msgid "badly formed order key string in state file! [%1] ... ignored."
+msgstr ""
+
+#: libs/ardour/route.cc:1673 libs/ardour/route.cc:1761
+msgid "[control]"
+msgstr ""
+
+#: libs/ardour/route.cc:1693
+msgid "Route %1: unknown mix group \"%2 in saved state (ignored)"
+msgstr ""
+
+#: libs/ardour/send.cc:99
+msgid "XML node describing a send is missing a Redirect node"
+msgstr ""
+
+#: libs/ardour/session.cc:111
+msgid "Could not resolve path: %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session.cc:123
+msgid "cannot check session path %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session.cc:153
+msgid "cannot check statefile %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session.cc:189
+msgid "%1 is not an Ardour snapshot file"
+msgstr ""
+
+#: libs/ardour/session.cc:206
+msgid "cannot determine current working directory (%1)"
+msgstr ""
+
+#: libs/ardour/session.cc:223
+msgid "unknown file type for session %1"
+msgstr ""
+
+#: libs/ardour/session.cc:343
+msgid "monitor"
+msgstr ""
+
+#: libs/ardour/session.cc:351
+msgid "master"
+msgstr ""
+
+#: libs/ardour/session.cc:633
+msgid "could not setup Click I/O"
+msgstr ""
+
+#: libs/ardour/session.cc:654
+msgid "cannot setup Click I/O"
+msgstr ""
+
+#: libs/ardour/session.cc:676
+msgid "cannot create Auditioner: no auditioning of regions possible"
+msgstr ""
+
+#: libs/ardour/session.cc:688
+#, c-format
+msgid "out %<PRIu32>"
+msgstr ""
+
+#: libs/ardour/session.cc:700
+#, c-format
+msgid "in %<PRIu32>"
+msgstr ""
+
+#: libs/ardour/session.cc:714
+#, c-format
+msgid "out %<PRIu32>+%<PRIu32>"
+msgstr ""
+
+#: libs/ardour/session.cc:728
+#, c-format
+msgid "in %<PRIu32>+%<PRIu32>"
+msgstr ""
+
+#: libs/ardour/session.cc:761
+msgid "cannot setup master inputs"
+msgstr ""
+
+#: libs/ardour/session.cc:769
+msgid "cannot setup master outputs"
+msgstr ""
+
+#: libs/ardour/session.cc:780
+msgid "Master Out"
+msgstr ""
+
+#: libs/ardour/session.cc:852
+msgid "cannot setup control inputs"
+msgstr ""
+
+#: libs/ardour/session.cc:860
+msgid "cannot set up master outputs"
+msgstr ""
+
+#: libs/ardour/session.cc:1043
+msgid "Session: you can't use that location for auto punch (start <= end)"
+msgstr ""
+
+#: libs/ardour/session.cc:1080
+msgid "Session: you can't use a mark for auto loop"
+msgstr ""
+
+#: libs/ardour/session.cc:1452
+msgid "feedback loop setup between %1 and %2"
+msgstr ""
+
+#: libs/ardour/session.cc:1629 libs/ardour/session.cc:1750
+msgid "cannot configure %1 in/%2 out configuration for new audio track"
+msgstr ""
+
+#: libs/ardour/session.cc:1687
+msgid "Session: could not create new audio track."
+msgstr ""
+
+#: libs/ardour/session.cc:1800
+msgid "Session: could not create new audio route."
+msgstr ""
+
+#: libs/ardour/session.cc:2319
+msgid "cannot create new name for region \"%1\""
+msgstr ""
+
+#: libs/ardour/session.cc:2383
+msgid "too many regions with names like %1"
+msgstr ""
+
+#: libs/ardour/session.cc:2883
+msgid "There are already %1 recordings for %2, which I consider too many."
+msgstr ""
+
+#: libs/ardour/session.cc:3085
+msgid "Cannot compile tape track regexp for use (%1)"
+msgstr ""
+
+#: libs/ardour/session.cc:3232
+msgid "programming error: unknown type of Insert created!"
+msgstr ""
+
+#: libs/ardour/session.cc:3238
+msgid "programming error: unknown type of Redirect created!"
+msgstr ""
+
+#: libs/ardour/session.cc:3261
+msgid "programming error: unknown type of Insert deleted!"
+msgstr ""
+
+#: libs/ardour/session.cc:3267
+msgid "programming error: unknown type of Redirect deleted!"
+msgstr ""
+
+#: libs/ardour/session.cc:3573
+msgid "too many bounced versions of playlist \"%1\""
+msgstr ""
+
+#: libs/ardour/session.cc:3582
+msgid "cannot create new audio file \"%1\" for %2"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:85 libs/ardour/session_butler.cc:90
+msgid "UI: cannot set O_NONBLOCK on butler request pipe (%1)"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:95
+msgid "Session: could not create butler thread"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:183
+msgid "poll on butler request pipe failed (%1)"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:190
+msgid "Error on butler thread request pipe: fd=%1 err=%2"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:231
+msgid "Error reading from butler request pipe"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:268
+msgid "Butler read ahead failure on dstream %1"
+msgstr ""
+
+#: libs/ardour/session_butler.cc:311
+msgid "Butler write-behind failure on dstream %1"
+msgstr ""
+
+#: libs/ardour/session_click.cc:160
+msgid "cannot open click soundfile %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session_click.cc:169
+msgid "cannot read data from click soundfile"
+msgstr ""
+
+#: libs/ardour/session_click.cc:196
+msgid "cannot open click emphasis soundfile %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session_click.cc:204
+msgid "cannot read data from click emphasis soundfile"
+msgstr ""
+
+#: libs/ardour/session_command.cc:49
+msgid "Tried to reconstitute a MementoCommand with no contents, failing. id="
+msgstr ""
+
+#: libs/ardour/session_command.cc:95
+msgid "could not reconstitute MementoCommand from XMLNode. id="
+msgstr ""
+
+#: libs/ardour/session_events.cc:161
+msgid "Session: cannot have two events of type %1 at the same frame (%2)."
+msgstr ""
+
+#: libs/ardour/session_events.cc:422
+msgid "Programming error: illegal event type in process_event (%1)"
+msgstr ""
+
+#: libs/ardour/session_export.cc:63
+msgid "Export: no output file specified"
+msgstr ""
+
+#: libs/ardour/session_export.cc:164 libs/ardour/session_export.cc:169
+msgid "illegal frame range in export specification"
+msgstr ""
+
+#: libs/ardour/session_export.cc:174
+msgid "Bad data width size. Report me!"
+msgstr ""
+
+#: libs/ardour/session_export.cc:204
+msgid "Export: cannot open output file \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_export.cc:214
+msgid "cannot initialize sample rate conversion: %1"
+msgstr ""
+
+#: libs/ardour/session_export.cc:316
+msgid "an error occured during sample rate conversion: %1"
+msgstr ""
+
+#: libs/ardour/session_export.cc:327
+msgid "warning, leftover frames overflowed, glitches might occur in output"
+msgstr ""
+
+#: libs/ardour/session_export.cc:418
+msgid "Export: could not write data to output file (%1)"
+msgstr ""
+
+#: libs/ardour/session_export.cc:502
+msgid "%1: cannot seek to %2 for export"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:95
+msgid "Ardour is slaved to MTC - port cannot be reset"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:110
+msgid "unknown port %1 requested for MTC"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:435
+msgid "Error reading from MIDI port %1"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:804
+msgid "Session: could not send full MIDI time code"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:863
+msgid "Session: cannot send quarter-frame MTC message (%1)"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:971
+msgid "MMC: cannot send command %1%2%3"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1078
+msgid "UI: cannot set O_NONBLOCK on signal read pipe (%1)"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1083
+msgid "UI: cannot set O_NONBLOCK on signal write pipe (%1)"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1088
+msgid "Session: could not create transport thread"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1117
+msgid "cannot send signal to midi thread! (%1)"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1212
+msgid "MIDI thread poll failed (%1)"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1224
+msgid "Error on transport thread request pipe"
+msgstr ""
+
+#: libs/ardour/session_midi.cc:1251
+msgid "Error reading from transport request pipe"
+msgstr ""
+
+#: libs/ardour/session_process.cc:104
+msgid "Session: error in no roll for %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:103
+msgid "Could not use path %1 (%s)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:131
+msgid "end"
+msgstr ""
+
+#: libs/ardour/session_state.cc:132
+msgid "start"
+msgstr ""
+
+#: libs/ardour/session_state.cc:443
+msgid "Session: cannot create session dir \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:450
+msgid "Session: cannot create session peakfile dir \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:457
+msgid "Session: cannot create session sounds dir \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:464
+msgid "Session: cannot create session dead sounds dir \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:471
+msgid "Session: cannot create session automation dir \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:500
+msgid "Could not open %1 for writing mix template"
+msgstr ""
+
+#: libs/ardour/session_state.cc:506
+msgid "Could not open mix template %1 for reading"
+msgstr ""
+
+#: libs/ardour/session_state.cc:548
+msgid "Session: could not load diskstream via XML state"
+msgstr ""
+
+#: libs/ardour/session_state.cc:597
+msgid "could not backup old state file, current state not saved."
+msgstr ""
+
+#: libs/ardour/session_state.cc:612
+msgid "state could not be saved to %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:619
+msgid "could not remove corrupt state file %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:623
+msgid "could not restore state file from backup %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:693
+msgid "%1: session state information file \"%2\" doesn't exist!"
+msgstr ""
+
+#: libs/ardour/session_state.cc:704 libs/ardour/session_state.cc:2824
+msgid "Could not understand ardour file %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:988
+msgid "programming error: Session: incorrect XML node sent to set_state()"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1047
+msgid "Session: XML state has no options section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1051
+msgid "Session: XML state has no sources section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1058
+msgid "Session: XML state has no Regions section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1065
+msgid "Session: XML state has no playlists section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1084
+msgid "Session: XML state has no diskstreams section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1091
+msgid "Session: XML state has no connections section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1098
+msgid "Session: XML state has no locations section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1131
+msgid "Session: XML state has no edit groups section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1138
+msgid "Session: XML state has no mix groups section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1145
+msgid "Session: XML state has no Tempo Map section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1152
+msgid "Session: XML state has no routes section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1159
+msgid "Session: XML state has no click section"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1202
+msgid "Session: cannot create Route from XML description."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1243
+msgid "Session: cannot create Region from XML description."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1271
+msgid "Session: XMLNode describing a AudioRegion is incomplete (no source)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1279 libs/ardour/session_state.cc:1300
+msgid ""
+"Session: XMLNode describing a AudioRegion references an unknown source id =%1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1285 libs/ardour/session_state.cc:1306
+msgid ""
+"Session: XMLNode describing a AudioRegion references a non-audio source id =%"
+"1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1377
+msgid "Session: cannot create Source from XML description."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1396
+msgid ""
+"Found a sound file that cannot be used by Ardour. Talk to the progammers."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1418
+msgid "Could not create mix templates directory \"%1\" (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1432
+msgid "Template \"%1\" already exists - new version not created"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1439
+msgid "mix template not saved"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1498
+msgid "cannot create session directory \"%1\"; ignored"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1509
+msgid "cannot create sounds directory \"%1\"; ignored"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1518
+msgid "cannot create dead sounds directory \"%1\"; ignored"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1527
+msgid "cannot create peak file directory \"%1\"; ignored"
+msgstr ""
+
+#: libs/ardour/session_state.cc:1659 libs/ardour/session_state.cc:1680
+msgid "Session: cannot create Playlist from XML description."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1719
+msgid "Session: cannot create Named Selection from XML description."
+msgstr ""
+
+#: libs/ardour/session_state.cc:1872
+msgid "Unknown node \"%1\" found in Connections list from state file"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2677
+msgid "cannot remove dead sound file %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2778
+msgid "could not backup old history file, current history not saved."
+msgstr ""
+
+#: libs/ardour/session_state.cc:2786
+msgid "history could not be saved to %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2794
+msgid "could not remove corrupt history file %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2798
+msgid "could not restore history file from backup %1"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2816
+msgid "Loading history from '%1'."
+msgstr ""
+
+#: libs/ardour/session_state.cc:2819
+msgid "%1: session history file \"%2\" doesn't exist!"
+msgstr ""
+
+#: libs/ardour/session_state.cc:2861
+msgid "Couldn't figure out how to make a Command out of a %1 XMLNode."
+msgstr ""
+
+#: libs/ardour/session_time.cc:370
+msgid "Unknown JACK transport state %1 in sync callback"
+msgstr ""
+
+#: libs/ardour/session_timefx.cc:79
+msgid "tempoize: error creating name for new audio file based on %1"
+msgstr ""
+
+#: libs/ardour/session_timefx.cc:88
+msgid "tempoize: error creating new audio file %1 (%2)"
+msgstr ""
+
+#: libs/ardour/session_timefx.cc:113
+msgid "tempoize: error reading data from %1"
+msgstr ""
+
+#: libs/ardour/session_timefx.cc:126 libs/ardour/session_timefx.cc:138
+msgid "error writing tempo-adjusted data to %1"
+msgstr ""
+
+#: libs/ardour/session_timefx.cc:144
+msgid "timefx code failure. please notify ardour-developers."
+msgstr ""
+
+#: libs/ardour/session_transport.cc:117
+msgid "Cannot loop - no loop range defined"
+msgstr ""
+
+#: libs/ardour/session_transport.cc:474
+msgid ""
+"Seamless looping cannot be supported while Ardour is using JACK transport.\n"
+"Recommend changing the configured options"
+msgstr ""
+
+#: libs/ardour/session_transport.cc:743
+msgid ""
+"Global varispeed cannot be supported while Ardour is connected to JACK "
+"transport control"
+msgstr ""
+
+#: libs/ardour/session_transport.cc:933
+msgid "please stop the transport before adjusting slave settings"
+msgstr ""
+
+#: libs/ardour/session_transport.cc:966
+msgid "No MTC port defined: MTC slaving is impossible."
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:15
+msgid "WAV"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:16
+msgid "AIFF"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:17
+msgid "raw (no header)"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:18
+msgid "PAF (Ensoniq Paris)"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:19
+msgid "AU (Sun/NeXT)"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:20
+msgid "IRCAM"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:21
+msgid "W64 (64 bit WAV)"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:26
+msgid ".wav"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:27
+msgid ".aiff"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:28
+msgid ".raw"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:29
+msgid ".paf"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:30
+msgid ".au"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:31
+msgid ".ircam"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:32
+msgid ".w64"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:47
+msgid "16 bit"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:48
+msgid "24 bit"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:49
+msgid "32 bit"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:50
+msgid "8 bit"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:51
+msgid "float"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:64
+msgid "Little-endian (Intel)"
+msgstr ""
+
+#: libs/ardour/sndfile_helpers.cc:65
+msgid "Big-endian (Mac)"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:143
+msgid "FileSource: cannot get host information for BWF header (%1)"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:167
+msgid ""
+"cannot set broadcast info for audio file %1 (%2); dropping broadcast info "
+"for this file"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:216
+msgid "SndFileSource: cannot open file \"%1\" for %2 (%3)"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:222
+msgid ""
+"SndFileSource: file only contains %1 channels; %2 is invalid as a channel "
+"number"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:327
+msgid "SndFileSource: could not seek to frame %1 within %2 (%3)"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:378
+msgid "programming error: %1 %2"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:486 libs/ardour/sndfilesource.cc:507
+msgid ""
+"cannot set broadcast info for audio file %1; Dropping broadcast info for "
+"this file"
+msgstr ""
+
+#: libs/ardour/sndfilesource.cc:521
+msgid "%1: cannot seek to %2"
+msgstr ""
+
+#: libs/ardour/state_manager.cc:47
+msgid "cleared history"
+msgstr ""
+
+#: libs/ardour/state_manager.cc:60
+msgid ""
+"programming error: illegal state ID (%1) passed to StateManager::set_state() "
+"(range = 0-%2)"
+msgstr ""
+
+#: libs/ardour/tempo.cc:67
+msgid "TempoSection XML node has no \"start\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:75
+msgid "TempoSection XML node has an illegal \"start\" value"
+msgstr ""
+
+#: libs/ardour/tempo.cc:82
+msgid "TempoSection XML node has no \"beats-per-minute\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:87
+msgid "TempoSection XML node has an illegal \"beats_per_minute\" value"
+msgstr ""
+
+#: libs/ardour/tempo.cc:92
+msgid "TempoSection XML node has no \"movable\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:131
+msgid "MeterSection XML node has no \"start\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:139
+msgid "MeterSection XML node has an illegal \"start\" value"
+msgstr ""
+
+#: libs/ardour/tempo.cc:146
+msgid "MeterSection XML node has no \"beats-per-bar\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:151
+msgid "MeterSection XML node has an illegal \"beats-per-bar\" value"
+msgstr ""
+
+#: libs/ardour/tempo.cc:156
+msgid "MeterSection XML node has no \"note-type\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:161
+msgid "MeterSection XML node has an illegal \"note-type\" value"
+msgstr ""
+
+#: libs/ardour/tempo.cc:166
+msgid "MeterSection XML node has no \"movable\" property"
+msgstr ""
+
+#: libs/ardour/tempo.cc:259
+msgid "move metric"
+msgstr ""
+
+#: libs/ardour/tempo.cc:330
+msgid "metric removed"
+msgstr ""
+
+#: libs/ardour/tempo.cc:373
+msgid "add tempo"
+msgstr ""
+
+#: libs/ardour/tempo.cc:402
+msgid "replace tempo"
+msgstr ""
+
+#: libs/ardour/tempo.cc:435
+msgid "add meter"
+msgstr ""
+
+#: libs/ardour/tempo.cc:463
+msgid "replaced meter"
+msgstr ""
+
+#: libs/ardour/tempo.cc:483 libs/ardour/tempo.cc:499
+msgid "programming error: no tempo section in tempo map!"
+msgstr ""
+
+#: libs/ardour/tempo.cc:538
+msgid "programming error: unhandled MetricSection type"
+msgstr ""
+
+#: libs/ardour/tempo.cc:1265 libs/ardour/tempo.cc:1277
+msgid "Tempo map: could not set new state, restoring old one."
+msgstr ""
+
+#: libs/ardour/tempo.cc:1301
+msgid "load XML data"
+msgstr ""
+
+#: libs/ardour/utils.cc:237
+msgid "illegal or badly-formed string used for path (%1)"
+msgstr ""
+
+#: libs/ardour/utils.cc:242
+msgid "path (%1) is ambiguous"
+msgstr ""
+
+#: libs/ardour/utils.cc:304 libs/ardour/utils.cc:323
+msgid "Splice Edit"
+msgstr "Fogredigering"
+
+#: libs/ardour/utils.cc:306 libs/ardour/utils.cc:319
+msgid "Slide Edit"
+msgstr "Glidredigering"
+
+#: libs/ardour/utils.cc:309
+msgid "programming error: unknown edit mode string \"%1\""
+msgstr ""
+
+#: libs/ardour/utils.cc:330 libs/ardour/utils.cc:359
+msgid "Internal"
+msgstr "Intern"
+
+#: libs/ardour/utils.cc:334 libs/ardour/utils.cc:355
+msgid "MTC"
+msgstr ""
+
+#: libs/ardour/utils.cc:338 libs/ardour/utils.cc:352
+msgid "JACK"
+msgstr ""
+
+#: libs/ardour/utils.cc:342
+msgid "programming error: unknown slave source string \"%1\""
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:178
+msgid "cannot create VST chunk directory: %1"
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:186
+msgid "cannot check VST chunk directory: %1"
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:193
+msgid "%1 exists but is not a directory"
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:231
+msgid "Bad node sent to VSTPlugin::set_state"
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:334 libs/ardour/vst_plugin.cc:345
+msgid "no support for presets using chunks at this time"
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:495
+msgid "VST: cannot load module from \"%1\""
+msgstr ""
+
+#: libs/ardour/vst_plugin.cc:500
+msgid "You asked ardour to not use any VST plugins"
+msgstr ""
+
+#: libs/ardour/audio_unit.cc:48
+msgid "AudioUnit: Could not convert CAComponent to CAAudioUnit"
+msgstr ""
diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc
index 09d650b069..adad79e2a3 100644
--- a/libs/ardour/redirect.cc
+++ b/libs/ardour/redirect.cc
@@ -108,101 +108,77 @@ Redirect::set_placement (const string& str, void *src)
}
}
+/* NODE STRUCTURE
+
+ <Automation [optionally with visible="...." ]>
+ <parameter-N>
+ <AutomationList id=N>
+ <events>
+ X1 Y1
+ X2 Y2
+ ....
+ </events>
+ </parameter-N>
+ <Automation>
+*/
+
int
-Redirect::load_automation (string path)
-{
- string fullpath;
+Redirect::set_automation_state (const XMLNode& node)
+{
+ Glib::Mutex::Lock lm (_automation_lock);
- if (path[0] == '/') { // legacy
- fullpath = path;
- } else {
- fullpath = _session.automation_dir();
- fullpath += path;
- }
- ifstream in (fullpath.c_str());
+ parameter_automation.clear ();
- if (!in) {
- warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
- return 1;
- }
+ XMLNodeList nlist = node.children();
+ XMLNodeIterator niter;
- Glib::Mutex::Lock lm (_automation_lock);
- set<uint32_t> tosave;
- parameter_automation.clear ();
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+ uint32_t param;
- while (in) {
- double when;
- double value;
- uint32_t port;
+ if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
+ error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
+ continue;
+ }
- in >> port; if (!in) break;
- in >> when; if (!in) goto bad;
- in >> value; if (!in) goto bad;
-
- AutomationList& al = automation_list (port);
- al.add (when, value);
- tosave.insert (port);
- }
-
- for (set<uint32_t>::iterator i = tosave.begin(); i != tosave.end(); ++i) {
- automation_list (*i).save_state (_("loaded from disk"));
+ AutomationList& al = automation_list (param);
+ if (al.set_state (*(*niter)->children().front())) {
+ goto bad;
+ }
}
-
+
return 0;
bad:
- error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+ error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
parameter_automation.clear ();
return -1;
}
-int
-Redirect::save_automation (string path)
+XMLNode&
+Redirect::get_automation_state ()
{
Glib::Mutex::Lock lm (_automation_lock);
+ XMLNode* node = new XMLNode (X_("Automation"));
string fullpath;
if (parameter_automation.empty()) {
- return 1;
- }
-
- fullpath = _session.automation_dir();
- fullpath += path;
-
- ofstream out (fullpath.c_str());
-
- if (!out) {
- error << string_compose(_("%1: cannot open %2 to store automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
- return -1;
+ return *node;
}
- AutomationList::const_iterator i;
map<uint32_t,AutomationList*>::iterator li;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
- for (i = (*li).second->begin(); i != (*li).second->end(); ++i) {
-
- out << (*li).first << ' ' << (*i)->when << ' ' << (*i)->value << endl;
-
- if (!out) {
- break;
- }
- }
+
+ XMLNode* child;
- if (i != (*li).second->end()) {
- unlink (fullpath.c_str());
- error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg;
- return -1;
- }
- }
-
- if (li != parameter_automation.end()) {
- unlink (fullpath.c_str());
- error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg;
- return -1;
+ char buf[64];
+ stringstream str;
+ snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
+ child = new XMLNode (buf);
+ child->add_child_nocopy (li->second->get_state ());
}
- return 0;
+ return *node;
}
XMLNode&
@@ -214,7 +190,6 @@ Redirect::get_state (void)
XMLNode&
Redirect::state (bool full_state)
{
- char buf[64];
XMLNode* node = new XMLNode (state_node_name);
stringstream sstr;
@@ -228,65 +203,24 @@ Redirect::state (bool full_state)
if (full_state) {
- string path;
- string legal_name;
+ XMLNode& automation = get_automation_state();
- path = _session.snap_name();
- path += "-redirect-";
- id().print (buf, sizeof (buf));
- path += buf;
- path += ".automation";
-
- /* XXX we didn't ask for a state save, we asked for the current state.
- FIX ME!
- */
-
- switch (save_automation (path)) {
- case -1:
- error << string_compose(_("Could not get state from Redirect (%1). Problem with save_automation"), _name) << endmsg;
- break;
-
- case 0:
- XMLNode *aevents = node->add_child("Automation");
-
- for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
- if (x != visible_parameter_automation.begin()) {
- sstr << ' ';
- }
- sstr << *x;
+ for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
+ if (x != visible_parameter_automation.begin()) {
+ sstr << ' ';
}
-
- aevents->add_property ("path", path);
- aevents->add_property ("visible", sstr.str());
- break;
+ sstr << *x;
}
- }
- return *node;
-}
+ automation.add_property ("visible", sstr.str());
-void
-Redirect::what_has_automation (set<uint32_t>& s) const
-{
- Glib::Mutex::Lock lm (_automation_lock);
- map<uint32_t,AutomationList*>::const_iterator li;
-
- for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
- s.insert ((*li).first);
+ node->add_child_nocopy (automation);
}
-}
-void
-Redirect::what_has_visible_automation (set<uint32_t>& s) const
-{
- Glib::Mutex::Lock lm (_automation_lock);
- set<uint32_t>::const_iterator li;
-
- for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) {
- s.insert (*li);
- }
+ return *node;
}
+
int
Redirect::set_state (const XMLNode& node)
{
@@ -308,14 +242,15 @@ Redirect::set_state (const XMLNode& node)
IO::set_state (**niter);
have_io = true;
- } else if ((*niter)->name() == "Automation") {
+ } else if ((*niter)->name() == X_("Automation")) {
+
XMLProperty *prop;
if ((prop = (*niter)->property ("path")) != 0) {
- load_automation (prop->value());
+ old_set_automation_state (*(*niter));
} else {
- warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+ set_automation_state (*(*niter));
}
if ((prop = (*niter)->property ("visible")) != 0) {
@@ -364,6 +299,102 @@ Redirect::set_state (const XMLNode& node)
return 0;
}
+int
+Redirect::old_set_automation_state (const XMLNode& node)
+{
+ const XMLProperty *prop;
+
+ if ((prop = node.property ("path")) != 0) {
+ load_automation (prop->value());
+ } else {
+ warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+ }
+
+ if ((prop = node.property ("visible")) != 0) {
+ uint32_t what;
+ stringstream sstr;
+
+ visible_parameter_automation.clear ();
+
+ sstr << prop->value();
+ while (1) {
+ sstr >> what;
+ if (sstr.fail()) {
+ break;
+ }
+ mark_automation_visible (what, true);
+ }
+ }
+
+ return 0;
+}
+
+int
+Redirect::load_automation (string path)
+{
+ string fullpath;
+
+ if (path[0] == '/') { // legacy
+ fullpath = path;
+ } else {
+ fullpath = _session.automation_dir();
+ fullpath += path;
+ }
+ ifstream in (fullpath.c_str());
+
+ if (!in) {
+ warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
+ return 1;
+ }
+
+ Glib::Mutex::Lock lm (_automation_lock);
+ set<uint32_t> tosave;
+ parameter_automation.clear ();
+
+ while (in) {
+ double when;
+ double value;
+ uint32_t port;
+
+ in >> port; if (!in) break;
+ in >> when; if (!in) goto bad;
+ in >> value; if (!in) goto bad;
+
+ AutomationList& al = automation_list (port);
+ al.add (when, value);
+ tosave.insert (port);
+ }
+
+ return 0;
+
+ bad:
+ error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+ parameter_automation.clear ();
+ return -1;
+}
+
+
+void
+Redirect::what_has_automation (set<uint32_t>& s) const
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+ map<uint32_t,AutomationList*>::const_iterator li;
+
+ for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
+ s.insert ((*li).first);
+ }
+}
+
+void
+Redirect::what_has_visible_automation (set<uint32_t>& s) const
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+ set<uint32_t>::const_iterator li;
+
+ for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) {
+ s.insert (*li);
+ }
+}
AutomationList&
Redirect::automation_list (uint32_t parameter)
{
@@ -437,34 +468,9 @@ Redirect::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_even
}
void
-Redirect::store_state (RedirectState& state) const
-{
- state.active = _active;
-}
-
-Change
-Redirect::restore_state (StateManager::State& state)
-{
- RedirectState* rstate = dynamic_cast<RedirectState*> (&state);
- set_active (rstate->active, this);
- return Change (0);
-}
-
-StateManager::State*
-Redirect::state_factory (std::string why) const
-{
- RedirectState* state = new RedirectState (why);
-
- store_state (*state);
-
- return state;
-}
-
-void
Redirect::set_active (bool yn, void* src)
{
_active = yn;
- save_state (_("active_changed"));
active_changed (this, src);
_session.set_dirty ();
}
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 3853559e10..6d8c71b563 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -265,13 +265,43 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
Region::~Region ()
{
- /* derived classes must call notify_callbacks() and then emit GoingAway */
+ if (_playlist) {
+ for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+ (*i)->remove_playlist (_playlist);
+ }
+ }
+
+ notify_callbacks ();
+ GoingAway (); /* EMIT SIGNAL */
}
void
Region::set_playlist (Playlist* pl)
{
- _playlist = pl;
+ if (pl == _playlist) {
+ return;
+ }
+
+ Playlist* old_playlist = _playlist;
+
+ if (pl) {
+ if (old_playlist) {
+ for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+ (*i)->remove_playlist (old_playlist);
+ (*i)->add_playlist (_playlist);
+ }
+ } else {
+ for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+ (*i)->add_playlist (_playlist);
+ }
+ }
+ } else {
+ if (old_playlist) {
+ for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+ (*i)->remove_playlist (old_playlist);
+ }
+ }
+ }
}
void
@@ -337,6 +367,24 @@ Region::first_edit ()
}
}
+bool
+Region::at_natural_position () const
+{
+ if (!_playlist) {
+ return false;
+ }
+
+ boost::shared_ptr<Region> whole_file_region = get_parent();
+
+ if (whole_file_region) {
+ if (_position == whole_file_region->position() + _start) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void
Region::move_to_natural_position (void *src)
{
@@ -1180,14 +1228,17 @@ Region::verify_start_mutable (jack_nframes_t& new_start)
}
boost::shared_ptr<Region>
-Region::get_parent()
+Region::get_parent() const
{
- boost::shared_ptr<Region> r;
-
if (_playlist) {
- r = _playlist->session().find_whole_file_parent (*this);
+ boost::shared_ptr<Region> r;
+ boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
+
+ if (grrr2 && (r = _playlist->session().find_whole_file_parent (grrr2))) {
+ return boost::static_pointer_cast<Region> (r);
+ }
}
- return r;
+ return boost::shared_ptr<Region>();
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 308dbb57cb..5314c99632 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -63,13 +63,13 @@ Route::Route (Session& sess, string name, int input_min, int input_max, int outp
init ();
}
-Route::Route (Session& sess, const XMLNode& node)
- : IO (sess, "route"),
+Route::Route (Session& sess, const XMLNode& node, DataType default_type)
+ : IO (sess, *node.child ("IO"), default_type),
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
{
init ();
- set_state (node);
+ _set_state (node, false);
}
void
@@ -1313,7 +1313,6 @@ XMLNode&
Route::state(bool full_state)
{
XMLNode *node = new XMLNode("Route");
- XMLNode *aevents;
RedirectList:: iterator i;
char buf[32];
@@ -1374,26 +1373,6 @@ Route::state(bool full_state)
cmt->add_content (_comment);
}
- if (full_state) {
- string path;
-
- path = _session.snap_name();
- path += "-gain-";
- path += legalize_for_path (_name);
- path += ".automation";
-
- /* XXX we didn't ask for a state save, we asked for the current state.
- FIX ME!
- */
-
- if (save_automation (path)) {
- error << _("Could not get state of route. Problem with save_automation") << endmsg;
- }
-
- aevents = node->add_child ("Automation");
- aevents->add_property ("path", path);
- }
-
for (i = _redirects.begin(); i != _redirects.end(); ++i) {
node->add_child_nocopy((*i)->state (full_state));
}
@@ -1481,6 +1460,12 @@ Route::add_redirect_from_xml (const XMLNode& node)
int
Route::set_state (const XMLNode& node)
{
+ return _set_state (node, true);
+}
+
+int
+Route::_set_state (const XMLNode& node, bool call_base)
+{
XMLNodeList nlist;
XMLNodeConstIterator niter;
XMLNode *child;
@@ -1492,7 +1477,7 @@ Route::set_state (const XMLNode& node)
return -1;
}
- if ((prop = node.property ("flags")) != 0) {
+ if ((prop = node.property (X_("flags"))) != 0) {
int x;
sscanf (prop->value().c_str(), "0x%x", &x);
_flags = Flag (x);
@@ -1500,20 +1485,20 @@ Route::set_state (const XMLNode& node)
_flags = Flag (0);
}
- if ((prop = node.property ("default-type")) != 0) {
+ if ((prop = node.property (X_("default-type"))) != 0) {
_default_type = DataType(prop->value());
assert(_default_type != DataType::NIL);
}
- if ((prop = node.property ("phase-invert")) != 0) {
+ if ((prop = node.property (X_("phase-invert"))) != 0) {
set_phase_invert(prop->value()=="yes"?true:false, this);
}
- if ((prop = node.property ("active")) != 0) {
+ if ((prop = node.property (X_("active"))) != 0) {
set_active (prop->value() == "yes");
}
- if ((prop = node.property ("muted")) != 0) {
+ if ((prop = node.property (X_("muted"))) != 0) {
bool yn = prop->value()=="yes"?true:false;
/* force reset of mute status */
@@ -1523,7 +1508,7 @@ Route::set_state (const XMLNode& node)
mute_gain = desired_mute_gain;
}
- if ((prop = node.property ("soloed")) != 0) {
+ if ((prop = node.property (X_("soloed"))) != 0) {
bool yn = prop->value()=="yes"?true:false;
/* force reset of solo status */
@@ -1533,23 +1518,23 @@ Route::set_state (const XMLNode& node)
solo_gain = desired_solo_gain;
}
- if ((prop = node.property ("mute-affects-pre-fader")) != 0) {
+ if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
_mute_affects_pre_fader = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-post-fader")) != 0) {
+ if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
_mute_affects_post_fader = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-control-outs")) != 0) {
+ if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
_mute_affects_control_outs = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-main-outs")) != 0) {
+ if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
_mute_affects_main_outs = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("edit-group")) != 0) {
+ if ((prop = node.property (X_("edit-group"))) != 0) {
RouteGroup* edit_group = _session.edit_group_by_name(prop->value());
if(edit_group == 0) {
error << string_compose(_("Route %1: unknown edit group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
@@ -1558,7 +1543,7 @@ Route::set_state (const XMLNode& node)
}
}
- if ((prop = node.property ("order-keys")) != 0) {
+ if ((prop = node.property (X_("order-keys"))) != 0) {
long n;
@@ -1595,7 +1580,7 @@ Route::set_state (const XMLNode& node)
delete deferred_state;
}
- deferred_state = new XMLNode("deferred state");
+ deferred_state = new XMLNode(X_("deferred state"));
/* set parent class properties before anything else */
@@ -1603,7 +1588,7 @@ Route::set_state (const XMLNode& node)
child = *niter;
- if (child->name() == IO::state_node_name) {
+ if (child->name() == IO::state_node_name && call_base) {
IO::set_state (*child);
break;
@@ -1614,7 +1599,7 @@ Route::set_state (const XMLNode& node)
child = *niter;
- if (child->name() == "Send") {
+ if (child->name() == X_("Send")) {
if (!IO::ports_legal) {
@@ -1625,7 +1610,7 @@ Route::set_state (const XMLNode& node)
add_redirect_from_xml (*child);
}
- } else if (child->name() == "Insert") {
+ } else if (child->name() == X_("Insert")) {
if (!IO::ports_legal) {
@@ -1636,21 +1621,13 @@ Route::set_state (const XMLNode& node)
add_redirect_from_xml (*child);
}
- } else if (child->name() == "Automation") {
-
- XMLPropertyList plist;
- XMLPropertyConstIterator piter;
- XMLProperty *prop;
+ } else if (child->name() == X_("Automation")) {
- plist = child->properties();
- for (piter = plist.begin(); piter != plist.end(); ++piter) {
- prop = *piter;
- if (prop->name() == "path") {
- load_automation (prop->value());
- }
+ if ((prop = child->property (X_("path"))) != 0) {
+ load_automation (prop->value());
}
- } else if (child->name() == "ControlOuts") {
+ } else if (child->name() == X_("ControlOuts")) {
string coutname = _name;
coutname += _("[control]");
@@ -1658,25 +1635,25 @@ Route::set_state (const XMLNode& node)
_control_outs = new IO (_session, coutname);
_control_outs->set_state (**(child->children().begin()));
- } else if (child->name() == "Comment") {
+ } else if (child->name() == X_("Comment")) {
/* XXX this is a terrible API design in libxml++ */
XMLNode *cmt = *(child->children().begin());
_comment = cmt->content();
- } else if (child->name() == "extra") {
+ } else if (child->name() == X_("extra")) {
_extra_xml = new XMLNode (*child);
- } else if (child->name() == "solo") {
+ } else if (child->name() == X_("solo")) {
_solo_control.set_state (*child);
_session.add_controllable (&_solo_control);
- } else if (child->name() == "mute") {
+ } else if (child->name() == X_("mute")) {
_mute_control.set_state (*child);
_session.add_controllable (&_mute_control);
}
}
- if ((prop = node.property ("mix-group")) != 0) {
+ if ((prop = node.property (X_("mix-group"))) != 0) {
RouteGroup* mix_group = _session.mix_group_by_name(prop->value());
if (mix_group == 0) {
error << string_compose(_("Route %1: unknown mix group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
@@ -1936,6 +1913,10 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
{
Glib::RWLock::ReaderLock lm (redirect_lock);
+ if (!did_locate) {
+ automation_snapshot (now);
+ }
+
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
if (Config->get_plugins_stop_with_transport() && can_flush_redirects) {
@@ -1952,19 +1933,6 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
_roll_delay = _initial_delay;
}
-UndoAction
-Route::get_memento() const
-{
- void (Route::*pmf)(state_id_t) = &Route::set_state;
- return sigc::bind (mem_fun (*(const_cast<Route *>(this)), pmf), _current_state_id);
-}
-
-void
-Route::set_state (state_id_t id)
-{
- return;
-}
-
void
Route::input_change_handler (IOChange change, void *ignored)
{
@@ -2048,6 +2016,15 @@ int
Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick,
bool can_record, bool rec_monitors_input)
{
+ {
+ Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
+ if (lm.locked()) {
+ // automation snapshot can also be called from the non-rt context
+ // and it uses the redirect list, so we take the lock out here
+ automation_snapshot (_session.transport_frame());
+ }
+ }
+
if ((n_outputs().get_total() == 0 && _redirects.empty()) || n_inputs().get_total() == 0 || !_active) {
silence (nframes, offset);
return 0;
@@ -2181,6 +2158,16 @@ Route::set_latency_delay (nframes_t longest_session_latency)
}
}
+void
+Route::automation_snapshot (nframes_t now)
+{
+ IO::automation_snapshot (now);
+
+ for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
+ (*i)->automation_snapshot (now);
+ }
+}
+
Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp)
: Controllable (name), route (s), type(tp)
{
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index 2c2a152416..73dbf11ad5 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -37,7 +37,6 @@ Send::Send (Session& s, Placement p)
: Redirect (s, s.next_send_name(), p)
{
_metering = false;
- save_state (_("initial state"));
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -50,7 +49,6 @@ Send::Send (Session& s, const XMLNode& node)
throw failed_constructor();
}
- save_state (_("initial state"));
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -58,7 +56,6 @@ Send::Send (const Send& other)
: Redirect (other._session, other._session.next_send_name(), other.placement())
{
_metering = false;
- save_state (_("initial state"));
RedirectCreated (this); /* EMIT SIGNAL */
}
@@ -77,7 +74,7 @@ XMLNode&
Send::state(bool full)
{
XMLNode *node = new XMLNode("Send");
- node->add_child_nocopy (Redirect::state(full));
+ node->add_child_nocopy (Redirect::state (full));
return *node;
}
@@ -86,11 +83,15 @@ Send::set_state(const XMLNode& node)
{
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
-
+
+ /* Send has regular IO automation (gain, pan) */
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
break;
+ } else if ((*niter)->name() == X_("Automation")) {
+ IO::set_automation_state (*(*niter));
}
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 11cb658008..1b7c3be6dd 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -288,7 +288,7 @@ Session::Session (AudioEngine &eng,
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
if (new_session) {
- if (create (new_session, mix_template, _engine.frame_rate() * 60 * 5)) {
+ if (create (new_session, mix_template, compute_initial_length())) {
cerr << "create failed\n";
throw failed_constructor ();
}
@@ -342,12 +342,21 @@ Session::Session (AudioEngine &eng,
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
- n_physical_outputs = max (requested_physical_out, _engine.n_physical_outputs());
- n_physical_inputs = max (requested_physical_in, _engine.n_physical_inputs());
+ n_physical_outputs = _engine.n_physical_outputs();
+ n_physical_inputs = _engine.n_physical_inputs();
+
+ if (n_physical_inputs) {
+ n_physical_inputs = max (requested_physical_in, n_physical_inputs);
+ }
+
+ if (n_physical_outputs) {
+ n_physical_outputs = max (requested_physical_out, n_physical_outputs);
+ }
first_stage_init (fullpath, snapshot_name);
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
if (new_session) {
if (create (new_session, 0, initial_length)) {
throw failed_constructor ();
@@ -410,7 +419,7 @@ Session::~Session ()
/* clear history so that no references to objects are held any more */
- history.clear ();
+ _history.clear ();
/* clear state tree so that no references to objects are held any more */
@@ -1331,8 +1340,10 @@ Session::set_frame_rate (nframes_t frames_per_second)
sync_time_vars();
+ Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
+
// XXX we need some equivalent to this, somehow
- // DestructiveFileSource::setup_standard_crossfades (frames_per_second);
+ // SndFileSource::setup_standard_crossfades (frames_per_second);
set_dirty();
@@ -1824,12 +1835,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
<< endmsg;
}
- for (uint32_t x = 0; x < bus->n_inputs().get(DataType::AUDIO); ++x) {
+ for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().get(DataType::AUDIO); ++x) {
port = "";
-
+
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
- port = physinputs[((n+x)%n_physical_inputs)];
+ port = physinputs[((n+x)%n_physical_inputs)];
}
if (port.length() && bus->connect_input (bus->input (x), port, this)) {
@@ -1837,7 +1848,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
}
}
- for (uint32_t x = 0; x < bus->n_outputs().get(DataType::AUDIO); ++x) {
+ for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().get(DataType::AUDIO); ++x) {
port = "";
@@ -1950,8 +1961,9 @@ Session::remove_route (shared_ptr<Route> route)
{
RCUWriter<RouteList> writer (routes);
shared_ptr<RouteList> rs = writer.get_copy ();
- rs->remove (route);
+ rs->remove (route);
+
/* deleting the master out seems like a dumb
idea, but its more of a UI policy issue
than our concern.
@@ -2564,7 +2576,7 @@ Session::remove_region (boost::weak_ptr<Region> weak_region)
}
boost::shared_ptr<Region>
-Session::find_whole_file_parent (Region& child)
+Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
{
RegionList::iterator i;
boost::shared_ptr<Region> region;
@@ -2577,13 +2589,13 @@ Session::find_whole_file_parent (Region& child)
if (region->whole_file()) {
- if (child.source_equivalent (region)) {
+ if (child->source_equivalent (region)) {
return region;
}
}
}
- return boost::shared_ptr<AudioRegion> ();
+ return boost::shared_ptr<Region> ();
}
void
@@ -2596,32 +2608,38 @@ Session::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vec
int
Session::destroy_region (boost::shared_ptr<Region> region)
{
- boost::shared_ptr<AudioRegion> aregion;
-
- if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) {
- return 0;
- }
-
- if (aregion->playlist()) {
- aregion->playlist()->destroy_region (region);
- }
-
vector<boost::shared_ptr<Source> > srcs;
-
- for (uint32_t n = 0; n < aregion->n_channels(); ++n) {
- srcs.push_back (aregion->source (n));
+
+ {
+ boost::shared_ptr<AudioRegion> aregion;
+
+ if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) {
+ return 0;
+ }
+
+ if (aregion->playlist()) {
+ aregion->playlist()->destroy_region (region);
+ }
+
+ for (uint32_t n = 0; n < aregion->n_channels(); ++n) {
+ srcs.push_back (aregion->source (n));
+ }
}
+ region->drop_references ();
+
for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
-
- if ((*i).use_count() == 1) {
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i);
+ if (!(*i)->used()) {
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i);
+
if (afs) {
(afs)->mark_for_remove ();
}
(*i)->drop_references ();
+
+ cerr << "source was not used by any playlist\n";
}
}
@@ -3198,6 +3216,20 @@ Session::add_playlist (Playlist* playlist)
}
void
+Session::get_playlists (vector<Playlist*>& s)
+{
+ {
+ Glib::Mutex::Lock lm (playlist_lock);
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ s.push_back (*i);
+ }
+ for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+ s.push_back (*i);
+ }
+ }
+}
+
+void
Session::track_playlist (Playlist* pl, bool inuse)
{
PlaylistList::iterator x;
@@ -3970,13 +4002,14 @@ Session::nbusses () const
}
void
-Session::add_curve(Curve *curve)
+Session::add_automation_list(AutomationList *al)
{
- curves[curve->id()] = curve;
+ automation_lists[al->id()] = al;
}
-void
-Session::add_automation_list(AutomationList *al)
+nframes_t
+Session::compute_initial_length ()
{
- automation_lists[al->id()] = al;
+ return _engine.frame_rate() * 60 * 5;
}
+
diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc
index 5fd6d70983..f09c7232d7 100644
--- a/libs/ardour/session_click.cc
+++ b/libs/ardour/session_click.cc
@@ -84,7 +84,7 @@ Session::click (nframes_t start, nframes_t nframes, nframes_t offset)
break;
}
}
-
+
run_clicks:
memset (buf, 0, sizeof (Sample) * nframes);
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index d71ba34fc7..5816f1c6b7 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -3,9 +3,13 @@
#include <pbd/memento_command.h>
#include <ardour/diskstream.h>
#include <ardour/playlist.h>
+#include <ardour/audioplaylist.h>
+#include <ardour/audio_track.h>
#include <ardour/tempo.h>
#include <ardour/audiosource.h>
#include <ardour/audioregion.h>
+#include <ardour/midi_source.h>
+#include <ardour/midi_region.h>
#include <pbd/error.h>
using namespace PBD;
#include "i18n.h"
@@ -13,7 +17,7 @@ using namespace PBD;
namespace ARDOUR {
-void Session::register_with_memento_command_factory(PBD::ID id, StatefulDestructible *ptr)
+void Session::register_with_memento_command_factory(PBD::ID id, PBD::StatefulThingWithGoingAway *ptr)
{
registry[id] = ptr;
}
@@ -49,41 +53,37 @@ Command *Session::memento_command_factory(XMLNode *n)
{
error << _("Tried to reconstitute a MementoCommand with no contents, failing. id=") << id.to_s() << endmsg;
return 0;
- }
-
-
- /* create command */
- string obj_T = n->children().front()->name();
- if (obj_T == "AudioRegion" || obj_T == "MidiRegion" || obj_T == "Region") {
+ }
+
+ /* create command */
+ string obj_T = n->property ("type_name")->value();
+ if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (MidiRegion).name() || obj_T == typeid (Region).name()) {
if (regions.count(id))
return new MementoCommand<Region>(*regions[id], before, after);
- } else if (obj_T == "AudioSource" || obj_T == "MidiSource") {
+ } else if (obj_T == typeid (AudioSource).name() || obj_T == typeid (MidiSource).name()) {
if (sources.count(id))
return new MementoCommand<Source>(*sources[id], before, after);
- } else if (obj_T == "Location") {
+ } else if (obj_T == typeid (Location).name()) {
return new MementoCommand<Location>(*_locations.get_location_by_id(id), before, after);
- } else if (obj_T == "Locations") {
+ } else if (obj_T == typeid (Locations).name()) {
return new MementoCommand<Locations>(_locations, before, after);
- } else if (obj_T == "TempoMap") {
+ } else if (obj_T == typeid (TempoMap).name()) {
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
- } else if (obj_T == "Playlist" || obj_T == "AudioPlaylist") {
+ } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
if (Playlist *pl = playlist_by_name(child->property("name")->value()))
return new MementoCommand<Playlist>(*pl, before, after);
- } else if (obj_T == "Route") { // includes AudioTrack
+ } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) {
return new MementoCommand<Route>(*route_by_id(id), before, after);
- } else if (obj_T == "Curve") {
- if (curves.count(id))
- return new MementoCommand<Curve>(*curves[id], before, after);
- } else if (obj_T == "AutomationList") {
+ } else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
if (automation_lists.count(id))
return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
} else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here
- return new MementoCommand<StatefulDestructible>(*registry[id], before, after);
+ return new MementoCommand<PBD::StatefulThingWithGoingAway>(*registry[id], before, after);
}
/* we failed */
- error << _("could not reconstitute MementoCommand from XMLNode. id=") << id.to_s() << endmsg;
- return 0;
+ error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg;
+ return 0 ;
}
// solo
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index ff79a47e6b..bcc9b730ba 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -195,7 +195,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
/* default short fade = 15ms */
Crossfade::set_short_xfade_length ((nframes_t) floor (Config->get_short_xfade_seconds() * frame_rate()));
- DestructiveFileSource::setup_standard_crossfades (frame_rate());
+ SndFileSource::setup_standard_crossfades (frame_rate());
last_mmc_step.tv_sec = 0;
last_mmc_step.tv_usec = 0;
@@ -250,10 +250,9 @@ Session::first_stage_init (string fullpath, string snapshot_name)
Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
- Curve::CurveCreated.connect (mem_fun (*this, &Session::add_curve));
AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
- Controllable::GoingAway.connect (mem_fun (*this, &Session::remove_controllable));
+ Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable));
IO::MoreChannels.connect (mem_fun (*this, &Session::ensure_buffers));
@@ -533,7 +532,6 @@ Session::create (bool& new_session, string* mix_template, nframes_t initial_leng
_state_of_the_state = Clean;
if (save_state (_current_snapshot_name)) {
- save_history (_current_snapshot_name);
return -1;
}
@@ -858,13 +856,15 @@ Session::state(bool full_state)
boost::shared_ptr<AudioFileSource> fs;
if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
- boost::shared_ptr<DestructiveFileSource> dfs = boost::dynamic_pointer_cast<DestructiveFileSource> (fs);
/* Don't save sources that are empty, unless they're destructive (which are OK
if they are empty, because we will re-use them every time.)
*/
- if ( ! dfs && siter->second->length() == 0) {
- continue;
+
+ if (!fs->destructive()) {
+ if (fs->length() == 0) {
+ continue;
+ }
}
}
@@ -898,7 +898,20 @@ Session::state(bool full_state)
}
}
- node->add_child_nocopy (_locations.get_state());
+ if (full_state) {
+ node->add_child_nocopy (_locations.get_state());
+ } else {
+ // for a template, just create a new Locations, populate it
+ // with the default start and end, and get the state for that.
+ Locations loc;
+ Location* start = new Location(0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
+ Location* end = new Location(0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
+ start->set_end(0);
+ loc.add (start);
+ end->set_end(compute_initial_length());
+ loc.add (end);
+ node->add_child_nocopy (loc.get_state());
+ }
child = node->add_child ("Connections");
{
@@ -1026,8 +1039,6 @@ Session::set_state (const XMLNode& node)
return -1;
}
- StateManager::prohibit_save ();
-
if ((prop = node.property ("name")) != 0) {
_name = prop->value ();
}
@@ -1058,11 +1069,11 @@ Session::set_state (const XMLNode& node)
Path
extra
Options/Config
+ Locations
Sources
AudioRegions
AudioDiskstreams
Connections
- Locations
Routes
EditGroups
MixGroups
@@ -1085,6 +1096,39 @@ Session::set_state (const XMLNode& node)
error << _("Session: XML state has no options section") << endmsg;
}
+ if ((child = find_named_node (node, "Locations")) == 0) {
+ error << _("Session: XML state has no locations section") << endmsg;
+ goto out;
+ } else if (_locations.set_state (*child)) {
+ goto out;
+ }
+
+ Location* location;
+
+ if ((location = _locations.auto_loop_location()) != 0) {
+ set_auto_loop_location (location);
+ }
+
+ if ((location = _locations.auto_punch_location()) != 0) {
+ set_auto_punch_location (location);
+ }
+
+ if ((location = _locations.end_location()) == 0) {
+ _locations.add (end_location);
+ } else {
+ delete end_location;
+ end_location = location;
+ }
+
+ if ((location = _locations.start_location()) == 0) {
+ _locations.add (start_location);
+ } else {
+ delete start_location;
+ start_location = location;
+ }
+
+ AudioFileSource::set_header_position_offset (start_location->start());
+
if ((child = find_named_node (node, "Sources")) == 0) {
error << _("Session: XML state has no sources section") << endmsg;
goto out;
@@ -1132,39 +1176,6 @@ Session::set_state (const XMLNode& node)
goto out;
}
- if ((child = find_named_node (node, "Locations")) == 0) {
- error << _("Session: XML state has no locations section") << endmsg;
- goto out;
- } else if (_locations.set_state (*child)) {
- goto out;
- }
-
- Location* location;
-
- if ((location = _locations.auto_loop_location()) != 0) {
- set_auto_loop_location (location);
- }
-
- if ((location = _locations.auto_punch_location()) != 0) {
- set_auto_punch_location (location);
- }
-
- if ((location = _locations.end_location()) == 0) {
- _locations.add (end_location);
- } else {
- delete end_location;
- end_location = location;
- }
-
- if ((location = _locations.start_location()) == 0) {
- _locations.add (start_location);
- } else {
- delete start_location;
- start_location = location;
- }
-
- _locations.save_state (_("initial state"));
-
if ((child = find_named_node (node, "EditGroups")) == 0) {
error << _("Session: XML state has no edit groups section") << endmsg;
goto out;
@@ -1209,8 +1220,6 @@ Session::set_state (const XMLNode& node)
_state_of_the_state = Clean;
- StateManager::allow_save (_("initial state"), true);
-
if (state_was_pending) {
save_state (_current_snapshot_name);
remove_pending_capture_state ();
@@ -1220,8 +1229,6 @@ Session::set_state (const XMLNode& node)
return 0;
out:
- /* we failed, re-enable state saving but don't actually save internal state */
- StateManager::allow_save (X_("ignored"), false);
return ret;
}
@@ -2210,7 +2217,7 @@ Session::commit_reversible_command (Command *cmd)
gettimeofday (&now, 0);
current_trans->set_timestamp (now);
- history.add (current_trans);
+ _history.add (current_trans);
}
Session::GlobalRouteBooleanState
@@ -2568,6 +2575,8 @@ Session::cleanup_sources (Session::cleanup_report& rep)
capture files.
*/
+ cerr << "checking out source " << i->second->name() << " use_count = " << i->second.use_count() << endl;
+
if (i->second.use_count() == 1 && i->second->length() > 0) {
dead_sources.push_back (i->second);
@@ -2757,7 +2766,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
/* dump the history list */
- history.clear ();
+ _history.clear ();
/* save state so we don't end up a session file
referring to non-existent sources.
@@ -2908,7 +2917,7 @@ Session::save_history (string snapshot_name)
string xml_path;
string bak_path;
- tree.set_root (&history.get_state());
+ tree.set_root (&_history.get_state());
if (snapshot_name.empty()) {
snapshot_name = _current_snapshot_name;
@@ -2935,14 +2944,13 @@ Session::save_history (string snapshot_name)
* possible to fix.
*/
- if (unlink (xml_path.c_str()))
- {
- error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg;
+ if (unlink (xml_path.c_str())) {
+ error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg;
} else {
- if (rename (bak_path.c_str(), xml_path.c_str()))
- {
- error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg;
- }
+ if (rename (bak_path.c_str(), xml_path.c_str()))
+ {
+ error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg;
+ }
}
return -1;
@@ -2972,7 +2980,7 @@ Session::restore_history (string snapshot_name)
}
/* replace history */
- history.clear();
+ _history.clear();
for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
@@ -3005,7 +3013,7 @@ Session::restore_history (string snapshot_name)
}
}
- history.add (ut);
+ _history.add (ut);
}
return 0;
@@ -3137,6 +3145,10 @@ Session::config_changed (const char* parameter_name)
if (_mtc_port != 0) {
session_send_mtc = Config->get_send_mtc();
+ if (session_send_mtc) {
+ /* mark us ready to send */
+ next_quarter_frame_to_send = 0;
+ }
}
} else if (PARAM_IS ("send-mmc")) {
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 004261fe8e..e9c4e3785f 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -125,7 +125,7 @@ Session::request_play_loop (bool yn)
if (!yn && Config->get_seamless_loop() && transport_rolling()) {
// request an immediate locate to refresh the diskstreams
// after disabling looping
- request_locate (_transport_frame-1, true);
+ request_locate (_transport_frame-1, false);
}
}
@@ -377,9 +377,6 @@ Session::non_realtime_stop (bool abort)
}
}
}
-
- //FIXME
- //deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
#ifdef LEAVE_TRANSPORT_UNADJUSTED
}
diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc
index b308a74c36..4cf644e0e0 100644
--- a/libs/ardour/sndfile_helpers.cc
+++ b/libs/ardour/sndfile_helpers.cc
@@ -106,11 +106,11 @@ sndfile_endian_format_from_string (string str)
string
sndfile_file_ending_from_string (string str)
-{
+{
static vector<string> file_endings;
if (file_endings.empty()) {
- file_endings = PBD::internationalize((const char **) sndfile_file_endings_strings);
+ file_endings = I18N((const char **) sndfile_file_endings_strings);
}
for (int n = 0; sndfile_header_formats_strings[n]; ++n) {
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index fcc6a33d81..a30bfcf49b 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -28,6 +28,8 @@
#include <glibmm/miscutils.h>
#include <ardour/sndfilesource.h>
+#include <ardour/sndfile_helpers.h>
+#include <ardour/utils.h>
#include "i18n.h"
@@ -35,6 +37,14 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
+gain_t* SndFileSource::out_coefficient = 0;
+gain_t* SndFileSource::in_coefficient = 0;
+nframes_t SndFileSource::xfade_frames = 64;
+const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
+ AudioFileSource::Removable|
+ AudioFileSource::RemovableIfEmpty|
+ AudioFileSource::CanRename);
+
SndFileSource::SndFileSource (Session& s, const XMLNode& node)
: AudioFileSource (s, node)
{
@@ -164,22 +174,32 @@ SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, Heade
}
void
-SndFileSource::init (const string& idstr)
+SndFileSource::init (string idstr)
{
string::size_type pos;
string file;
+ // lets try to keep the object initalizations here at the top
+ xfade_buf = 0;
interleave_buf = 0;
interleave_bufsize = 0;
sf = 0;
_broadcast_info = 0;
+ string tmp_name;
+
if ((pos = idstr.find_last_of (':')) == string::npos) {
channel = 0;
- _name = Glib::path_get_basename (idstr);
+ tmp_name = idstr;
} else {
channel = atoi (idstr.substr (pos+1).c_str());
- _name = Glib::path_get_basename (idstr.substr (0, pos));
+ tmp_name = idstr.substr (0, pos);
+ }
+
+ if (is_embedded()) {
+ _name = tmp_name;
+ } else {
+ _name = Glib::path_get_basename (tmp_name);
}
/* although libsndfile says we don't need to set this,
@@ -187,6 +207,17 @@ SndFileSource::init (const string& idstr)
*/
memset (&_info, 0, sizeof(_info));
+
+ _capture_start = false;
+ _capture_end = false;
+ file_pos = 0;
+
+ if (destructive()) {
+ xfade_buf = new Sample[xfade_frames];
+ timeline_position = header_position_offset;
+ }
+
+ AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
}
int
@@ -212,27 +243,14 @@ SndFileSource::open ()
_broadcast_info = new SF_BROADCAST_INFO;
memset (_broadcast_info, 0, sizeof (*_broadcast_info));
- /* lookup broadcast info */
-
- if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
-
- /* if the file has data but no broadcast info, then clearly, there is no broadcast info */
-
- if (_length) {
- delete _broadcast_info;
- _broadcast_info = 0;
- _flags = Flag (_flags & ~Broadcast);
- }
-
- set_timeline_position (header_position_offset);
+ bool timecode_info_exists;
- } else {
-
- /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
- of the time reference.
- */
+ set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
- set_timeline_position ( _broadcast_info->time_reference_low );
+ if (!timecode_info_exists) {
+ delete _broadcast_info;
+ _broadcast_info = 0;
+ _flags = Flag (_flags & ~Broadcast);
}
if (writable()) {
@@ -266,6 +284,10 @@ SndFileSource::~SndFileSource ()
if (_broadcast_info) {
delete _broadcast_info;
}
+
+ if (xfade_buf) {
+ delete [] xfade_buf;
+ }
}
float
@@ -352,6 +374,16 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
nframes_t
SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
{
+ if (destructive()) {
+ return destructive_write_unlocked (data, cnt);
+ } else {
+ return nondestructive_write_unlocked (data, cnt);
+ }
+}
+
+nframes_t
+SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
+{
if (!writable()) {
return 0;
}
@@ -403,6 +435,117 @@ SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
return cnt;
}
+nframes_t
+SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
+{
+ nframes_t old_file_pos;
+
+ if (!writable()) {
+ return 0;
+ }
+
+ if (_capture_start && _capture_end) {
+
+ /* start and end of capture both occur within the data we are writing,
+ so do both crossfades.
+ */
+
+ _capture_start = false;
+ _capture_end = false;
+
+ /* move to the correct location place */
+ file_pos = capture_start_frame - timeline_position;
+
+ // split cnt in half
+ nframes_t subcnt = cnt / 2;
+ nframes_t ofilepos = file_pos;
+
+ // fade in
+ if (crossfade (data, subcnt, 1) != subcnt) {
+ return 0;
+ }
+
+ file_pos += subcnt;
+ Sample * tmpdata = data + subcnt;
+
+ // fade out
+ subcnt = cnt - subcnt;
+ if (crossfade (tmpdata, subcnt, 0) != subcnt) {
+ return 0;
+ }
+
+ file_pos = ofilepos; // adjusted below
+
+ } else if (_capture_start) {
+
+ /* start of capture both occur within the data we are writing,
+ so do the fade in
+ */
+
+ _capture_start = false;
+ _capture_end = false;
+
+ /* move to the correct location place */
+ file_pos = capture_start_frame - timeline_position;
+
+ if (crossfade (data, cnt, 1) != cnt) {
+ return 0;
+ }
+
+ } else if (_capture_end) {
+
+ /* end of capture both occur within the data we are writing,
+ so do the fade out
+ */
+
+ _capture_start = false;
+ _capture_end = false;
+
+ if (crossfade (data, cnt, 0) != cnt) {
+ return 0;
+ }
+
+ } else {
+
+ /* in the middle of recording */
+
+ if (write_float (data, file_pos, cnt) != cnt) {
+ return 0;
+ }
+ }
+
+ old_file_pos = file_pos;
+ update_length (file_pos, cnt);
+ file_pos += cnt;
+
+ if (_build_peakfiles) {
+ PeakBuildRecord *pbr = 0;
+
+ if (pending_peak_builds.size()) {
+ pbr = pending_peak_builds.back();
+ }
+
+ if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
+
+ /* the last PBR extended to the start of the current write,
+ so just extend it again.
+ */
+
+ pbr->cnt += cnt;
+ } else {
+ pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
+ }
+
+ _peaks_built = false;
+ }
+
+ if (_build_peakfiles) {
+ queue_for_peaks (shared_from_this ());
+ }
+
+ return cnt;
+}
+
int
SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
{
@@ -499,8 +642,10 @@ SndFileSource::set_header_timeline_position ()
nframes_t
SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
{
- if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) != frame_pos) {
- error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg;
+ if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
+ char errbuf[256];
+ sf_error_str (0, errbuf, sizeof (errbuf) - 1);
+ error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
return 0;
}
@@ -516,3 +661,286 @@ SndFileSource::natural_position() const
{
return timeline_position;
}
+
+bool
+SndFileSource::set_destructive (bool yn)
+{
+ if (yn) {
+ _flags = Flag (_flags | Destructive);
+ if (!xfade_buf) {
+ xfade_buf = new Sample[xfade_frames];
+ }
+ clear_capture_marks ();
+ timeline_position = header_position_offset;
+ } else {
+ _flags = Flag (_flags & ~Destructive);
+ timeline_position = 0;
+ /* leave xfade buf alone in case we need it again later */
+ }
+
+ return true;
+}
+
+void
+SndFileSource::clear_capture_marks ()
+{
+ _capture_start = false;
+ _capture_end = false;
+}
+
+void
+SndFileSource::mark_capture_start (nframes_t pos)
+{
+ if (destructive()) {
+ if (pos < timeline_position) {
+ _capture_start = false;
+ } else {
+ _capture_start = true;
+ capture_start_frame = pos;
+ }
+ }
+}
+
+void
+SndFileSource::mark_capture_end()
+{
+ if (destructive()) {
+ _capture_end = true;
+ }
+}
+
+nframes_t
+SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
+{
+ nframes_t xfade = min (xfade_frames, cnt);
+ nframes_t nofade = cnt - xfade;
+ Sample* fade_data = 0;
+ nframes_t fade_position = 0; // in frames
+ ssize_t retval;
+ nframes_t file_cnt;
+
+ if (fade_in) {
+ fade_position = file_pos;
+ fade_data = data;
+ } else {
+ fade_position = file_pos + nofade;
+ fade_data = data + nofade;
+ }
+
+ if (fade_position > _length) {
+
+ /* read starts beyond end of data, just memset to zero */
+
+ file_cnt = 0;
+
+ } else if (fade_position + xfade > _length) {
+
+ /* read ends beyond end of data, read some, memset the rest */
+
+ file_cnt = _length - fade_position;
+
+ } else {
+
+ /* read is entirely within data */
+
+ file_cnt = xfade;
+ }
+
+ if (file_cnt) {
+
+ if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
+ if (retval >= 0 && errno == EAGAIN) {
+ /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
+ * short or no data there */
+ memset (xfade_buf, 0, xfade * sizeof(Sample));
+ } else {
+ error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
+ return 0;
+ }
+ }
+ }
+
+ if (file_cnt != xfade) {
+ nframes_t delta = xfade - file_cnt;
+ memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
+ }
+
+ if (nofade && !fade_in) {
+ if (write_float (data, file_pos, nofade) != nofade) {
+ error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+ return 0;
+ }
+ }
+
+ if (xfade == xfade_frames) {
+
+ nframes_t n;
+
+ /* use the standard xfade curve */
+
+ if (fade_in) {
+
+ /* fade new material in */
+
+ for (n = 0; n < xfade; ++n) {
+ xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
+ }
+
+ } else {
+
+
+ /* fade new material out */
+
+ for (n = 0; n < xfade; ++n) {
+ xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
+ }
+ }
+
+ } else if (xfade < xfade_frames) {
+
+ gain_t in[xfade];
+ gain_t out[xfade];
+
+ /* short xfade, compute custom curve */
+
+ compute_equal_power_fades (xfade, in, out);
+
+ for (nframes_t n = 0; n < xfade; ++n) {
+ xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
+ }
+
+ } else if (xfade) {
+
+ /* long xfade length, has to be computed across several calls */
+
+ }
+
+ if (xfade) {
+ if (write_float (xfade_buf, fade_position, xfade) != xfade) {
+ error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+ return 0;
+ }
+ }
+
+ if (fade_in && nofade) {
+ if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
+ error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+ return 0;
+ }
+ }
+
+ return cnt;
+}
+
+nframes_t
+SndFileSource::last_capture_start_frame () const
+{
+ if (destructive()) {
+ return capture_start_frame;
+ } else {
+ return 0;
+ }
+}
+
+void
+SndFileSource::handle_header_position_change ()
+{
+ if (destructive()) {
+ if ( _length != 0 ) {
+ error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
+ //in the future, pop up a dialog here that allows user to regenerate file with new start offset
+ } else if (writable()) {
+ timeline_position = header_position_offset;
+ set_header_timeline_position (); //this will get flushed if/when the file is recorded to
+ }
+ }
+}
+
+void
+SndFileSource::setup_standard_crossfades (nframes_t rate)
+{
+ /* This static method is assumed to have been called by the Session
+ before any DFS's are created.
+ */
+
+ xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
+
+ if (out_coefficient) {
+ delete [] out_coefficient;
+ }
+
+ if (in_coefficient) {
+ delete [] in_coefficient;
+ }
+
+ out_coefficient = new gain_t[xfade_frames];
+ in_coefficient = new gain_t[xfade_frames];
+
+ compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
+}
+
+void
+SndFileSource::set_timeline_position (int64_t pos)
+{
+ // destructive track timeline postion does not change
+ // except at instantion or when header_position_offset
+ // (session start) changes
+
+ if (!destructive()) {
+ AudioFileSource::set_timeline_position (pos);
+ }
+}
+
+int
+SndFileSource::get_soundfile_info (string path, SoundFileInfo& info, string& error_msg)
+{
+ SNDFILE *sf;
+ SF_INFO sf_info;
+ SF_BROADCAST_INFO binfo;
+ bool timecode_exists;
+
+ sf_info.format = 0; // libsndfile says to clear this before sf_open().
+
+ if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
+ char errbuf[256];
+ error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
+ return false;
+ }
+
+ info.samplerate = sf_info.samplerate;
+ info.channels = sf_info.channels;
+ info.length = sf_info.frames;
+ info.format_name = string_compose("Format: %1, %2",
+ sndfile_major_format(sf_info.format),
+ sndfile_minor_format(sf_info.format));
+
+ memset (&binfo, 0, sizeof (binfo));
+ info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
+
+ if (!timecode_exists) {
+ info.timecode = 0;
+ }
+
+ sf_close (sf);
+
+ return true;
+}
+
+int64_t
+SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
+{
+ if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
+ exists = false;
+ return (header_position_offset);
+ }
+
+ /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
+ of the time reference.
+ */
+
+ exists = true;
+ int64_t ret = (uint32_t) binfo->time_reference_high;
+ ret <<= 32;
+ ret |= (uint32_t) binfo->time_reference_low;
+ return ret;
+}
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index 86ca0c55f2..8f0afd3507 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -34,6 +34,7 @@
#include <pbd/pthread_utils.h>
#include <ardour/source.h>
+#include <ardour/playlist.h>
#include "i18n.h"
@@ -51,6 +52,7 @@ Source::Source (Session& s, string name, DataType type)
_name = name;
_timestamp = 0;
_length = 0;
+ _in_use = 0;
}
Source::Source (Session& s, const XMLNode& node)
@@ -59,6 +61,7 @@ Source::Source (Session& s, const XMLNode& node)
{
_timestamp = 0;
_length = 0;
+ _in_use = 0;
if (set_state (node) || _type == DataType::NIL) {
throw failed_constructor();
@@ -127,3 +130,24 @@ Source::update_length (jack_nframes_t pos, jack_nframes_t cnt)
}
}
+void
+Source::add_playlist (Playlist* pl)
+{
+ _playlists.insert (pl);
+}
+
+void
+Source::remove_playlist (Playlist* pl)
+{
+ std::set<Playlist*>::iterator x;
+
+ if ((x = _playlists.find (pl)) != _playlists.end()) {
+ _playlists.erase (x);
+ }
+}
+
+uint32_t
+Source::used () const
+{
+ return _playlists.size();
+}
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index e9564a6193..001af609dc 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -110,7 +110,7 @@ SourceFactory::create (Session& s, const XMLNode& node)
return ret;
}
-
+
return boost::shared_ptr<Source>();
}
@@ -163,7 +163,6 @@ SourceFactory::create (Session& s, const XMLNode& node)
boost::shared_ptr<Source>
SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
{
-<<<<<<< .working
if (type == DataType::AUDIO) {
if (flags & Destructive) {
boost::shared_ptr<Source> ret (new DestructiveFileSource (s, idstr, flags));
@@ -197,7 +196,7 @@ SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFil
return ret;
}
-
+
return boost::shared_ptr<Source>();
}
@@ -220,9 +219,6 @@ SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFil
} else if (type == DataType::MIDI) {
boost::shared_ptr<Source> ret (new SMFSource (s, idstr, SMFSource::Flag(0))); // FIXME: flags?
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
if (announce) {
SourceCreated (ret);
}
@@ -239,7 +235,6 @@ boost::shared_ptr<Source>
SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce)
{
/* this might throw failed_constructor(), which is OK */
-
if (type == DataType::AUDIO) {
if (destructive) {
diff --git a/libs/ardour/sse_functions_64bit.s b/libs/ardour/sse_functions_64bit.s
index 997852eb5b..0242db3e77 100644
--- a/libs/ardour/sse_functions_64bit.s
+++ b/libs/ardour/sse_functions_64bit.s
@@ -602,3 +602,8 @@ x86_sse_compute_peak:
.size x86_sse_compute_peak, .-x86_sse_compute_peak
#; end proc
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
+
diff --git a/libs/ardour/state_manager.cc b/libs/ardour/state_manager.cc
deleted file mode 100644
index 153773ed30..0000000000
--- a/libs/ardour/state_manager.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <pbd/error.h>
-#include <ardour/state_manager.h>
-
-#include "i18n.h"
-
-using namespace ARDOUR;
-using namespace std;
-using namespace PBD;
-
-bool StateManager::_allow_save = true;
-sigc::signal<void,const char*> StateManager::SaveAllowed;
-
-StateManager::StateManager ()
-{
- _current_state_id = 0;
-}
-
-StateManager::~StateManager()
-{
-}
-
-void
-StateManager::prohibit_save ()
-{
- _allow_save = false;
-}
-
-void
-StateManager::allow_save (const char* why, bool do_save)
-{
- _allow_save = true;
- if (do_save) {
- SaveAllowed (why);
- SaveAllowed.slots().erase (SaveAllowed.slots().begin(), SaveAllowed.slots().end());
- }
-}
-
-void
-StateManager::drop_all_states ()
-{
- for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
- delete *i;
- }
-
- states.clear ();
-
- save_state (_("cleared history"));
-}
-
-void
-StateManager::use_state (state_id_t id)
-{
- Change what_changed;
- state_id_t n;
- StateMap::iterator i;
-
- for (n = 0, i = states.begin(); n < id && i != states.end(); ++n, ++i);
-
- if (n != id || i == states.end()) {
- fatal << string_compose (_("programming error: illegal state ID (%1) passed to "
- "StateManager::set_state() (range = 0-%2)"), id, states.size()-1)
- << endmsg;
- /*NOTREACHED*/
- return;
- }
-
- what_changed = restore_state (**i);
- _current_state_id = id;
- send_state_changed (what_changed);
-}
-
-void
-StateManager::save_state (std::string why)
-{
- if (!should_save_state())
- return;
-
- if (!_allow_save) {
- SaveAllowed.connect (mem_fun (*this, &StateManager::save_state));
- return;
- }
-
- states.push_back (state_factory (why));
- _current_state_id = states.size() - 1;
-}
-
-void
-StateManager::send_state_changed (Change what_changed)
-{
- StateChanged (what_changed);
-}
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 3cc5420c67..0ff94324bb 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -206,7 +206,6 @@ TempoMap::TempoMap (nframes_t fr)
_frame_rate = fr;
last_bbt_valid = false;
BBT_Time start;
- in_set_state = false;
start.bars = 1;
start.beats = 1;
@@ -222,8 +221,6 @@ TempoMap::TempoMap (nframes_t fr)
metrics->push_back (t);
metrics->push_back (m);
-
- save_state (_("initial"));
}
TempoMap::~TempoMap ()
@@ -256,7 +253,6 @@ TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
section.set_start (corrected);
metrics->sort (cmp);
timestamp_metrics ();
- save_state (_("move metric"));
return 0;
}
@@ -265,7 +261,7 @@ void
TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
{
if (move_metric_section (tempo, when) == 0) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -273,7 +269,7 @@ void
TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
{
if (move_metric_section (meter, when) == 0) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -301,7 +297,7 @@ TempoMap::remove_tempo (const TempoSection& tempo)
}
if (removed) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -325,14 +321,10 @@ TempoMap::remove_meter (const MeterSection& tempo)
}
}
}
-
- if (removed) {
- save_state (_("metric removed"));
- }
}
if (removed) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -369,11 +361,9 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
where.ticks = 0;
do_insert (new TempoSection (where, tempo.beats_per_minute()));
-
- save_state (_("add tempo"));
}
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
void
@@ -397,14 +387,10 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
break;
}
}
-
- if (replaced) {
- save_state (_("replace tempo"));
- }
}
if (replaced) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -431,11 +417,9 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
where.ticks = 0;
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()));
-
- save_state (_("add meter"));
}
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
void
@@ -458,14 +442,10 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
break;
}
}
-
- if (replaced) {
- save_state (_("replaced meter"));
- }
}
if (replaced) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
@@ -1071,6 +1051,9 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
double beat_frame;
double beat_frames;
double frames_per_bar;
+ double delta_bars;
+ double delta_beats;
+ double dummy;
nframes_t limit;
meter = &first_meter ();
@@ -1100,6 +1083,10 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
Now start generating points.
*/
+ beats_per_bar = meter->beats_per_bar ();
+ frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
+ beat_frames = tempo->frames_per_beat (_frame_rate);
+
if (meter->frame() > tempo->frame()) {
bar = meter->start().bars;
beat = meter->start().beats;
@@ -1110,12 +1097,21 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
current = tempo->frame();
}
+ /* initialize current to point to the bar/beat just prior to the
+ lower frame bound passed in. assumes that current is initialized
+ above to be on a beat.
+ */
+
+ delta_bars = (lower-current) / frames_per_bar;
+ delta_beats = modf(delta_bars, &dummy) * beats_per_bar;
+ current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
+
+ // adjust bars and beats too
+ bar += (uint32_t) (floor(delta_bars));
+ beat += (uint32_t) (floor(delta_beats));
+
points = new BBTPointList;
- beats_per_bar = meter->beats_per_bar ();
- frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
- beat_frames = tempo->frames_per_beat (_frame_rate);
-
do {
if (i == metrics->end()) {
@@ -1197,6 +1193,10 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
beat = 1;
}
+ beats_per_bar = meter->beats_per_bar ();
+ frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
+ beat_frames = tempo->frames_per_beat (_frame_rate);
+
++i;
}
@@ -1246,8 +1246,6 @@ TempoMap::set_state (const XMLNode& node)
XMLNodeConstIterator niter;
Metrics old_metrics (*metrics);
- in_set_state = true;
-
metrics->clear();
nlist = node.children();
@@ -1287,20 +1285,9 @@ TempoMap::set_state (const XMLNode& node)
metrics->sort (cmp);
timestamp_metrics ();
}
-
- in_set_state = false;
}
- /* This state needs to be saved. This string will never be a part of the
- object's history though, because the allow_save flag is false during
- session load. This state will eventually be tagged "initial state",
- by a call to StateManager::allow_save from Session::set_state.
-
- If this state is not saved, there is no way to reach it through undo actions.
- */
- save_state(_("load XML data"));
-
- send_state_changed (Change (0));
+ StateChanged (Change (0));
return 0;
}
@@ -1323,65 +1310,3 @@ TempoMap::dump (std::ostream& o) const
}
}
-UndoAction
-TempoMap::get_memento () const
-{
- return sigc::bind (mem_fun (*(const_cast<TempoMap *> (this)), &StateManager::use_state), _current_state_id);
-}
-
-Change
-TempoMap::restore_state (StateManager::State& state)
-{
- Glib::RWLock::ReaderLock lm (lock);
-
- TempoMapState* tmstate = dynamic_cast<TempoMapState*> (&state);
-
- /* We can't just set the metrics pointer to the address of the metrics list
- stored in the state, cause this would ruin this state for restoring in
- the future. If they have the same address, they are the same list.
- Thus we need to copy all the elements from the state metrics list to the
- current metrics list.
- */
- metrics->clear();
- for (Metrics::iterator i = tmstate->metrics->begin(); i != tmstate->metrics->end(); ++i) {
- TempoSection *ts;
- MeterSection *ms;
-
- if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
- metrics->push_back (new TempoSection (*ts));
- } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
- metrics->push_back (new MeterSection (*ms));
- }
- }
-
- last_bbt_valid = false;
-
- return Change (0);
-}
-
-StateManager::State*
-TempoMap::state_factory (std::string why) const
-{
- TempoMapState* state = new TempoMapState (why);
-
- for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
- TempoSection *ts;
- MeterSection *ms;
-
- if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
- state->metrics->push_back (new TempoSection (*ts));
- } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
- state->metrics->push_back (new MeterSection (*ms));
- }
- }
-
- return state;
-}
-
-void
-TempoMap::save_state (std::string why)
-{
- if (!in_set_state) {
- StateManager::save_state (why);
- }
-}
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 053a866256..a5484813f9 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -50,8 +50,8 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
}
Track::Track (Session& sess, const XMLNode& node, DataType default_type)
- : Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type)
- , _rec_enable_control (*this)
+ : Route (sess, node),
+ _rec_enable_control (*this)
{
_freeze_record.state = NoFreeze;
_declickable = true;
@@ -183,18 +183,6 @@ Track::set_record_enable (bool yn, void *src)
_rec_enable_control.Changed ();
}
-void
-Track::set_mode (TrackMode m)
-{
- if (_diskstream) {
- if (_mode != m) {
- _mode = m;
- _diskstream->set_destructive (m == Destructive);
- ModeChanged();
- }
- }
-}
-
int
Track::set_name (string str, void *src)
{
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 9a841e81b4..9c94d32241 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -38,6 +38,7 @@
#endif
#include <pbd/error.h>
+#include <pbd/stacktrace.h>
#include <pbd/xml++.h>
#include <ardour/utils.h>
@@ -221,7 +222,7 @@ region_name_from_path (string path)
/* remove any "?R", "?L" or "?[a-z]" channel identifier */
string::size_type len = path.length();
-
+
if (len > 3 && (path[len-2] == '%' || path[len-2] == '?') &&
(path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
@@ -299,7 +300,7 @@ compute_equal_power_fades (nframes_t nframes, float* in, float* out)
const float pan_law_attenuation = -3.0f;
const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
- for (unsigned long n = 0; n < nframes; ++n) {
+ for (nframes_t n = 0; n < nframes; ++n) {
float inVal = in[n];
float outVal = 1 - inVal;
out[n] = outVal * (scale * outVal + 1.0f - scale);
@@ -407,3 +408,82 @@ meter_hold_to_float (MeterHold hold)
return 200.0f;
}
}
+
+AutoState
+ARDOUR::string_to_auto_state (std::string str)
+{
+ if (str == X_("Off")) {
+ return Off;
+ } else if (str == X_("Play")) {
+ return Play;
+ } else if (str == X_("Write")) {
+ return Write;
+ } else if (str == X_("Touch")) {
+ return Touch;
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg;
+ /*NOTREACHED*/
+ return Touch;
+}
+
+string
+ARDOUR::auto_state_to_string (AutoState as)
+{
+ /* to be used only for XML serialization, no i18n done */
+
+ switch (as) {
+ case Off:
+ return X_("Off");
+ break;
+ case Play:
+ return X_("Play");
+ break;
+ case Write:
+ return X_("Write");
+ break;
+ case Touch:
+ return X_("Touch");
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg;
+ /*NOTREACHED*/
+ return "";
+}
+
+AutoStyle
+ARDOUR::string_to_auto_style (std::string str)
+{
+ if (str == X_("Absolute")) {
+ return Absolute;
+ } else if (str == X_("Trim")) {
+ return Trim;
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg;
+ /*NOTREACHED*/
+ return Trim;
+}
+
+string
+ARDOUR::auto_style_to_string (AutoStyle as)
+{
+ /* to be used only for XML serialization, no i18n done */
+
+ switch (as) {
+ case Absolute:
+ return X_("Absolute");
+ break;
+ case Trim:
+ return X_("Trim");
+ break;
+ }
+
+ fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as) << endmsg;
+ /*NOTREACHED*/
+ return "";
+}
+
+extern "C" {
+ void c_stacktrace() { stacktrace (cerr); }
+}
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index 800c5a9856..5d7a303fc6 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -110,16 +110,6 @@ VSTPlugin::set_block_size (nframes_t nframes)
activate ();
}
-void
-VSTPlugin::store_state (PluginState& state)
-{
-}
-
-void
-VSTPlugin::restore_state (PluginState& state)
-{
-}
-
float
VSTPlugin::default_value (uint32_t port)
{
diff --git a/libs/clearlooks/SConscript b/libs/clearlooks/SConscript
new file mode 100644
index 0000000000..0df20efe56
--- /dev/null
+++ b/libs/clearlooks/SConscript
@@ -0,0 +1,23 @@
+import os.path
+
+Import ('env install_prefix')
+
+clearlooks = env.Copy()
+
+clearlooks.Replace(CCFLAGS = ' `pkg-config --cflags gtk+-2.0` ',
+ LINKFLAGS = ' `pkg-config --libs gtk+-2.0` ')
+
+libclearlooks = clearlooks.SharedLibrary('clearlooks', [
+ 'clearlooks_draw.c',
+ 'clearlooks_rc_style.c',
+ 'clearlooks_style.c',
+ 'clearlooks_theme_main.c',
+ 'support.c'
+])
+
+usable_libclearlooks = clearlooks.Install ('engines', libclearlooks)
+Default (usable_libclearlooks)
+
+env.Alias('install',
+ env.Install(os.path.join(install_prefix,'lib/ardour2/engines'),
+ libclearlooks))
diff --git a/libs/clearlooks/bits.c b/libs/clearlooks/bits.c
new file mode 100644
index 0000000000..1e871bc5d3
--- /dev/null
+++ b/libs/clearlooks/bits.c
@@ -0,0 +1,121 @@
+static unsigned char dot_intensity[] = {
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x98,0xb9,0xc6,0xb9,0x91,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0xb9,0xbd,0xac,0x9e,0x65,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0xc6,0xac,0x9e,0x96,0x5c,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0xb9,0x9e,0x96,0x62,0x55,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x91,0x65,0x5c,0x55,0x68,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,
+};
+static unsigned char dot_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x66,0xc4,0xff,0xc4,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x66,0xdf,0xff,0xff,0xff,0xdf,0x66,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc4,0xff,0xff,0xff,0xff,0xff,0xc4,0x00,0x00,0x00,
+0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc4,0xff,0xff,0xff,0xff,0xff,0xc4,0x00,0x00,0x00,
+0x00,0x00,0x00,0x66,0xdf,0xff,0xff,0xff,0xdf,0x66,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x66,0xc4,0xff,0xc4,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+static unsigned char circle_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x23,0x62,0x92,0xb3,0xb2,0x95,0x2b,0x00,0x00,0x00,
+0x00,0x00,0x3e,0xab,0xc9,0xeb,0xf9,0xf5,0xfd,0xff,0x57,0x00,0x00,
+0x00,0x1f,0xb5,0xd8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x00,
+0x00,0x67,0xb9,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9c,0x00,
+0x00,0x9a,0xe2,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0x00,
+0x00,0xba,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xc0,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0x00,
+0x00,0x9b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9c,0x00,
+0x00,0x2b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x00,
+0x00,0x00,0x57,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x00,0x00,
+0x00,0x00,0x00,0x2b,0x9c,0xe5,0xff,0xe5,0x9c,0x2b,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+static unsigned char outline_alpha[] = {
+0x00,0x00,0x00,0x4a,0xac,0xe9,0xff,0xe9,0xac,0x4a,0x00,0x00,0x00,
+0x00,0x00,0x98,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x98,0x00,0x00,
+0x00,0x98,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x98,0x00,
+0x4a,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,
+0xac,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xac,
+0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,
+0xac,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xac,
+0x4a,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,
+0x00,0x98,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x98,0x00,
+0x00,0x00,0x98,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x98,0x00,0x00,
+0x00,0x00,0x00,0x4a,0xac,0xe9,0xff,0xe9,0xac,0x4a,0x00,0x00,0x00,
+};
+static unsigned char inconsistent_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,
+0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,
+0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+static unsigned char check_base_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+static unsigned char check_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 11, 137, 151,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00, 9, 183, 172, 7,0x00,0x00,
+0x00,0x00, 12, 18,0x00,0x00, 3, 161, 233, 27,0x00,0x00,0x00,
+0x00,0x00, 199, 239, 101,0x00, 85, 253, 108,0x00,0x00,0x00,0x00,
+0x00,0x00, 83, 245, 250, 75, 206, 230, 8,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00, 104, 252, 243, 253, 124,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00, 2, 162, 255, 241, 28,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00, 18, 228, 163,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00, 78, 62,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+static unsigned char check_inconsistent_alpha[] = {
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
+0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
+0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
diff --git a/libs/clearlooks/clearlooks_draw.c b/libs/clearlooks/clearlooks_draw.c
new file mode 100644
index 0000000000..144be35152
--- /dev/null
+++ b/libs/clearlooks/clearlooks_draw.c
@@ -0,0 +1,1293 @@
+#include "clearlooks_draw.h"
+#include "clearlooks_style.h"
+
+#include "support.h"
+
+/** WANTED:
+ FASTER GRADIENT FILL FUNCTION, POSSIBLY USING XRENDER. **/
+
+static void cl_draw_borders (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r);
+
+static void cl_draw_line (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x1, int y1, int x2, int y2, CLBorderType border,
+ CLRectangle *r);
+
+static void cl_draw_corner (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height,
+ CLRectangle *r, CLCornerSide corner);
+
+static void cl_draw_fill (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r);
+
+void cl_draw_rectangle (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ if (r->fillgc)
+ {
+ cl_draw_fill(window, widget, style, x, y, width, height, r);
+ }
+
+ if (r->bordergc)
+ {
+ cl_draw_borders(window, widget, style, x, y, width, height, r);
+ }
+}
+
+
+static void cl_get_coords ( CLBorderType border,
+ int x, int y, int width, int height,
+ CLRectangle *r, int *x1, int *y1, int *x2, int *y2)
+{
+ switch (border)
+ {
+ case CL_BORDER_TOP:
+ *x1 = x + r->corners[CL_CORNER_TOPLEFT];
+ *x2 = *x1 + width - r->corners[CL_CORNER_TOPLEFT] - r->corners[CL_CORNER_TOPRIGHT] - 1;
+ *y1 = *y2 = y;
+ break;
+ case CL_BORDER_BOTTOM:
+ *x1 = x + r->corners[CL_CORNER_BOTTOMLEFT];
+ *x2 = *x1 + width - r->corners[CL_CORNER_BOTTOMLEFT] - r->corners[CL_CORNER_BOTTOMRIGHT] - 1;
+ *y1 = *y2 = y + height - 1;
+ break;
+ case CL_BORDER_LEFT:
+ *x1 = *x2 = x;
+ *y1 = y + r->corners[CL_CORNER_TOPLEFT];
+ *y2 = *y1 + height - r->corners[CL_CORNER_TOPLEFT] - r->corners[CL_CORNER_BOTTOMLEFT] - 1;
+ break;
+ case CL_BORDER_RIGHT:
+ *x1 = *x2 = x + width - 1;
+ *y1 = y + r->corners[CL_CORNER_TOPRIGHT];
+ *y2 = *y1 + height - r->corners[CL_CORNER_TOPRIGHT] - r->corners[CL_CORNER_BOTTOMRIGHT] - 1;
+ break;
+ }
+}
+
+void cl_draw_borders (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ int x1, y1, x2, y2, i;
+
+ if (r->bordergc == NULL)
+ return;
+
+ for ( i=0; i<4; i++) /* draw all four borders + corners */
+ {
+ cl_get_coords (i, x, y, width, height, r, &x1, &y1, &x2, &y2);
+ cl_draw_line (window, widget, style, x1, y1, x2, y2, i, r);
+ cl_draw_corner (window, widget, style, x, y, width, height, r, i );
+ }
+}
+
+
+static GdkColor cl_gc_get_foreground(GdkGC *gc)
+{
+ GdkGCValues values;
+ gdk_gc_get_values (gc, &values);
+ return values.foreground;
+}
+
+static void cl_draw_line (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x1, int y1, int x2, int y2, CLBorderType border,
+ CLRectangle *r)
+{
+ if (r->gradient_type == CL_GRADIENT_NONE ||
+ r->border_gradient.from == NULL || r->border_gradient.to == NULL )
+ {
+ gdk_draw_line (window, r->bordergc, x1, y1, x2, y2);
+ }
+ else if (r->gradient_type == CL_GRADIENT_HORIZONTAL && (border == CL_BORDER_TOP || border == CL_BORDER_BOTTOM))
+ {
+ draw_vgradient (window, r->bordergc, style,
+ x1, y1, x2-x1+1, 1,
+ r->border_gradient.from, r->border_gradient.to);
+ }
+ else if (r->gradient_type == CL_GRADIENT_VERTICAL && (border == CL_BORDER_LEFT || border == CL_BORDER_RIGHT))
+ {
+ draw_hgradient (window, r->bordergc, style,
+ x1, y1, 1, y2-y1+1,
+ r->border_gradient.from, r->border_gradient.to);
+ }
+ else
+ {
+ GdkColor tmp_color = cl_gc_get_foreground (r->bordergc);
+
+ if (r->gradient_type == CL_GRADIENT_HORIZONTAL && border == CL_BORDER_LEFT ||
+ r->gradient_type == CL_GRADIENT_VERTICAL && border == CL_BORDER_TOP)
+ gdk_gc_set_foreground (r->bordergc, r->border_gradient.from);
+ else
+ gdk_gc_set_foreground (r->bordergc, r->border_gradient.to);
+
+ gdk_draw_line (window, r->bordergc, x1, y1, x2, y2);
+
+ gdk_gc_set_foreground (r->bordergc, &tmp_color);
+ }
+}
+
+static GdkColor *cl_get_gradient_corner_color (CLRectangle *r, CLCornerSide corner)
+{
+ GdkColor *color;
+
+ if (r->border_gradient.from == NULL || r->border_gradient.to == NULL)
+ {
+ color = NULL;
+ }
+ else if ((r->gradient_type == CL_GRADIENT_HORIZONTAL && (corner == CL_CORNER_TOPLEFT || corner == CL_CORNER_BOTTOMLEFT)) ||
+ (r->gradient_type == CL_GRADIENT_VERTICAL && (corner == CL_CORNER_TOPLEFT || corner == CL_CORNER_TOPRIGHT)))
+ {
+ color = r->border_gradient.from;
+ }
+ else /* no gradient or other corner */
+ {
+ color = r->border_gradient.to;
+ }
+
+ return color;
+}
+
+static void cl_draw_corner (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height,
+ CLRectangle *r, CLCornerSide corner)
+{
+ GdkColor *color;
+ GdkColor aacolor; /* anti-aliasing color */
+ GdkGCValues values;
+ GdkColor tmp;
+ GdkColor *bgcolor;
+
+ int x1;
+ int y1;
+
+ if (r->corners[corner] == CL_CORNER_NONE)
+ return;
+
+ color = cl_get_gradient_corner_color (r, corner);
+ gdk_gc_get_values (r->bordergc, &values);
+
+ if (color == NULL)
+ {
+ tmp = values.foreground;
+ gdk_colormap_query_color (gtk_widget_get_colormap(widget), values.foreground.pixel, &tmp);
+ color = &tmp;
+ }
+
+ bgcolor = get_parent_bgcolor(widget);
+
+ if (bgcolor == NULL)
+ {
+ bgcolor = color;
+ }
+
+ blend (style->colormap, bgcolor, color, &aacolor, 70);
+
+ if (r->corners[corner] == CL_CORNER_ROUND)
+ {
+ x1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_BOTTOMLEFT) ? x+1 : x+width - 2;
+
+ y1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_TOPRIGHT) ? y+1 : y+height - 2;
+
+ gdk_gc_set_foreground (r->bordergc, color);
+ gdk_draw_point (window, r->bordergc, x1, y1);
+
+ gdk_gc_set_foreground (r->bordergc, &aacolor);
+
+ x1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_BOTTOMLEFT) ? x+1 : x+width-2;
+
+ y1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_TOPRIGHT) ? y : y+height-1;
+
+ gdk_draw_point (window, r->bordergc, x1, y1);
+
+ x1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_BOTTOMLEFT) ? x : x+width-1;
+
+ y1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_TOPRIGHT) ? y+1 : y+height-2;
+
+ gdk_draw_point (window, r->bordergc, x1, y1);
+
+ }
+ else if (r->corners[corner] == CL_CORNER_NARROW)
+ {
+ x1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_BOTTOMLEFT) ? x : x+width-1;
+
+ y1 = (corner == CL_CORNER_TOPLEFT ||
+ corner == CL_CORNER_TOPRIGHT) ? y : y+height-1;
+
+ gdk_gc_set_foreground (r->bordergc, &aacolor);
+ gdk_draw_point (window, r->bordergc, x1, y1);
+ }
+
+ gdk_gc_set_foreground (r->bordergc, &values.foreground);
+}
+
+static void cl_draw_fill (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ if (r->gradient_type == CL_GRADIENT_NONE ||
+ r->fill_gradient.from == NULL || r->fill_gradient.to == NULL)
+ {
+ gdk_draw_rectangle (window, r->fillgc, TRUE,
+ x+1, y+1, width-2, height-2);
+ }
+ else if (r->gradient_type == CL_GRADIENT_HORIZONTAL)
+ {
+ draw_vgradient (window, r->fillgc, gtk_widget_get_style(widget),
+ x+1, y+1, width-2, height-2,
+ r->fill_gradient.from, r->fill_gradient.to);
+ }
+ else if (r->gradient_type == CL_GRADIENT_VERTICAL)
+ {
+ draw_hgradient (window, r->fillgc, gtk_widget_get_style(widget),
+ x+1, y+1, width-2, height-2,
+ r->fill_gradient.from, r->fill_gradient.to);
+ }
+}
+
+void cl_rectangle_set_button(CLRectangle *r, GtkStyle *style,
+ GtkStateType state_type, gboolean has_default,
+ gboolean has_focus,
+ CLBorderType tl, CLBorderType tr,
+ CLBorderType bl, CLBorderType br)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int my_state_type = (state_type == GTK_STATE_ACTIVE) ? 2 : 0;
+ GdkGC *border_gc = clearlooks_style->border_gc[CL_BORDER_UPPER+my_state_type];
+
+
+ cl_rectangle_init (r, style->bg_gc[state_type],
+ clearlooks_style->border_gc[CL_BORDER_UPPER+my_state_type],
+ tl, tr, bl, br);
+
+ if (state_type != GTK_STATE_INSENSITIVE && !has_default)
+ {
+ cl_rectangle_set_gradient (&r->border_gradient,
+ &clearlooks_style->border[CL_BORDER_UPPER+my_state_type],
+ &clearlooks_style->border[CL_BORDER_LOWER+my_state_type]);
+ }
+ else if (has_default)
+ r->bordergc = style->black_gc;
+ else
+ r->bordergc = clearlooks_style->shade_gc[4];
+
+ r->gradient_type = CL_GRADIENT_VERTICAL;
+
+ r->topleft = (state_type != GTK_STATE_ACTIVE) ? style->light_gc[state_type] : clearlooks_style->shade_gc[4];
+ r->bottomright = (state_type != GTK_STATE_ACTIVE) ? clearlooks_style->shade_gc[1] : NULL;
+
+ shade (&style->bg[state_type], &r->tmp_color, 0.93);
+
+
+ cl_rectangle_set_gradient (&r->fill_gradient,
+ &style->bg[state_type],
+ &r->tmp_color);
+}
+
+void cl_rectangle_set_entry (CLRectangle *r, GtkStyle *style,
+ GtkStateType state_type,
+ CLBorderType tl, CLBorderType tr,
+ CLBorderType bl, CLBorderType br,
+ gboolean has_focus)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkGC *bordergc;
+
+ if (has_focus)
+ bordergc = clearlooks_style->spot3_gc;
+ else if (state_type != GTK_STATE_INSENSITIVE)
+ bordergc = clearlooks_style->border_gc[CL_BORDER_LOWER];
+ else
+ bordergc = clearlooks_style->shade_gc[3];
+
+ cl_rectangle_init (r, style->base_gc[state_type], bordergc,
+ tl, tr, bl, br);
+
+ if (state_type != GTK_STATE_INSENSITIVE )
+ r->topleft = (has_focus) ? clearlooks_style->spot1_gc
+ : style->bg_gc[GTK_STATE_NORMAL];
+
+ if (has_focus)
+ r->bottomright = clearlooks_style->spot1_gc;
+ else if (state_type == GTK_STATE_INSENSITIVE)
+ r->bottomright = style->base_gc[state_type];
+}
+
+void cl_draw_shadow(GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int x1, y1, x2, y2;
+
+ if (r->bottomright != NULL)
+ {
+ x1 = x+1+(r->corners[CL_CORNER_BOTTOMLEFT]/2);
+ y1 = y2 = y+height-2;
+ x2 = x+width - 1 - (1+r->corners[CL_CORNER_BOTTOMRIGHT]/2);
+
+ gdk_draw_line (window, r->bottomright, x1, y1, x2, y2);
+
+ x1 = x2 = x+width-2;
+ y1 = y+1+(r->corners[CL_CORNER_TOPRIGHT]/2);
+ y2 = y+height - 1 - (1+r->corners[CL_CORNER_BOTTOMRIGHT]/2);
+
+ gdk_draw_line (window, r->bottomright, x1, y1, x2, y2);
+ }
+
+ if (r->topleft != NULL)
+ {
+ x1 = x+1+(r->corners[CL_CORNER_TOPLEFT]/2);
+ y1 = y2 = y+1;
+ x2 = x+width-1-(1+r->corners[CL_CORNER_TOPRIGHT]/2);
+
+ gdk_draw_line (window, r->topleft, x1, y1, x2, y2);
+
+ x1 = x2 = x+1;
+ y1 = y+1+(r->corners[CL_CORNER_TOPLEFT]/2);
+ y2 = y+height-1-(1+r->corners[CL_CORNER_BOTTOMLEFT]/2);
+
+ gdk_draw_line (window, r->topleft, x1, y1, x2, y2);
+ }
+}
+
+void cl_rectangle_set_color (CLGradient *g, GdkColor *color)
+{
+ g->from = color;
+ g->to = color;
+}
+
+void cl_rectangle_set_gradient (CLGradient *g, GdkColor *from, GdkColor *to)
+{
+ g->from = from;
+ g->to = to;
+}
+
+void cl_rectangle_init (CLRectangle *r,
+ GdkGC *fillgc, GdkGC *bordergc,
+ int tl, int tr, int bl, int br)
+{
+ r->gradient_type = CL_GRADIENT_NONE;
+
+ r->border_gradient.from = r->border_gradient.to = NULL;
+ r->fill_gradient.from = r->fill_gradient.to = NULL;
+
+ r->fillgc = fillgc;
+ r->bordergc = bordergc;
+
+ r->topleft = NULL;
+ r->bottomright = NULL;
+
+ r->corners[CL_CORNER_TOPLEFT] = tl;
+ r->corners[CL_CORNER_TOPRIGHT] = tr;
+ r->corners[CL_CORNER_BOTTOMLEFT] = bl;
+ r->corners[CL_CORNER_BOTTOMRIGHT] = br;
+}
+
+void cl_rectangle_set_corners (CLRectangle *r, int tl, int tr, int bl, int br)
+{
+ r->corners[CL_CORNER_TOPLEFT] = tl;
+ r->corners[CL_CORNER_TOPRIGHT] = tr;
+ r->corners[CL_CORNER_BOTTOMLEFT] = bl;
+ r->corners[CL_CORNER_BOTTOMRIGHT] = br;
+}
+
+void cl_set_corner_sharpness (const gchar *detail, GtkWidget *widget, CLRectangle *r)
+{
+ if (widget->parent && GTK_IS_COMBO_BOX_ENTRY (widget->parent) || GTK_IS_COMBO (widget->parent))
+ {
+ gboolean rtl = get_direction (widget->parent) == GTK_TEXT_DIR_RTL;
+ int cl = rtl ? CL_CORNER_ROUND : CL_CORNER_NONE;
+ int cr = rtl ? CL_CORNER_NONE : CL_CORNER_ROUND;
+
+ cl_rectangle_set_corners (r, cl, cr, cl, cr);
+ }
+ else if (detail && !strcmp (detail, "spinbutton_up"))
+ {
+ gboolean rtl = get_direction (widget->parent) == GTK_TEXT_DIR_RTL;
+ int tl = rtl ? CL_CORNER_ROUND : CL_CORNER_NONE;
+ int tr = rtl ? CL_CORNER_NONE : CL_CORNER_ROUND;
+
+ cl_rectangle_set_corners (r, tl, tr,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+ }
+ else if (detail && !strcmp (detail, "spinbutton_down"))
+ {
+ gboolean rtl = get_direction (widget->parent) == GTK_TEXT_DIR_RTL;
+ int bl = rtl ? CL_CORNER_ROUND : CL_CORNER_NONE;
+ int br = rtl ? CL_CORNER_NONE : CL_CORNER_ROUND;
+
+ cl_rectangle_set_corners (r, CL_CORNER_NONE, CL_CORNER_NONE,
+ bl, br);
+ }
+ else
+ {
+ cl_rectangle_set_corners (r, CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+ };
+}
+
+void cl_rectangle_set_clip_rectangle (CLRectangle *r, GdkRectangle *area)
+{
+ if (area == NULL)
+ return;
+
+ if (r->fillgc)
+ gdk_gc_set_clip_rectangle (r->fillgc, area);
+
+ if (r->bordergc)
+ gdk_gc_set_clip_rectangle (r->bordergc, area);
+
+ if (r->topleft)
+ gdk_gc_set_clip_rectangle (r->topleft, area);
+
+ if (r->bottomright)
+ gdk_gc_set_clip_rectangle (r->bottomright, area);
+}
+
+void cl_rectangle_reset_clip_rectangle (CLRectangle *r)
+{
+ if (r->fillgc)
+ gdk_gc_set_clip_rectangle (r->fillgc, NULL);
+
+ if (r->bordergc)
+ gdk_gc_set_clip_rectangle (r->bordergc, NULL);
+
+ if (r->topleft)
+ gdk_gc_set_clip_rectangle (r->topleft, NULL);
+
+ if (r->bottomright)
+ gdk_gc_set_clip_rectangle (r->bottomright, NULL);
+}
+
+void cl_rectangle_reset (CLRectangle *r, GtkStyle *style)
+{
+ cl_rectangle_init (r,
+ NULL, NULL,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+}
+
+static void cl_progressbar_points_transform (GdkPoint *points, int npoints,
+ int offset, gboolean is_horizontal)
+{
+ int i;
+ for ( i=0; i<npoints; i++) {
+ if ( is_horizontal )
+ points[i].x += offset;
+ else
+ points[i].y += offset;
+ }
+}
+
+GdkPixmap* cl_progressbar_tile_new (GdkDrawable *drawable, GtkWidget *widget,
+ GtkStyle *style, gint height, gint offset)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int width = height;
+ int line = 0;
+ int center = width/2;
+ int xdir = 1;
+ int trans;
+
+ int stripe_width = height/2;
+ int topright = height + stripe_width;
+ int topright_div_2 = topright/2;
+
+ double shift;
+ GdkPoint points[4];
+
+ GtkProgressBarOrientation orientation = gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (widget));
+ gboolean is_horizontal = (orientation == GTK_PROGRESS_LEFT_TO_RIGHT || orientation == GTK_PROGRESS_RIGHT_TO_LEFT) ? 1 : 0;
+
+ GdkPixmap *tmp = gdk_pixmap_new (widget->window, width, height, -1);
+
+ GdkColor tmp_color;
+ shade (&clearlooks_style->spot2, &tmp_color, 0.90);
+
+ if (is_horizontal)
+ draw_hgradient (tmp, style->black_gc, style, 0, 0, width, height,
+ &clearlooks_style->spot2, &tmp_color );
+ else
+ draw_vgradient (tmp, style->black_gc, style, 0, 0, width, height,
+ &tmp_color, &clearlooks_style->spot2); /* TODO: swap for RTL */
+
+ if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT ||
+ orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
+ {
+ offset = -offset;
+ xdir = -1;
+ }
+
+ if (get_direction (widget) == GTK_TEXT_DIR_RTL)
+ offset = -offset;
+
+ if (is_horizontal)
+ {
+ points[0] = (GdkPoint){xdir*(topright - stripe_width - topright_div_2), 0}; /* topleft */
+ points[1] = (GdkPoint){xdir*(topright - topright_div_2), 0}; /* topright */
+ points[2] = (GdkPoint){xdir*(stripe_width - topright_div_2), height}; /* bottomright */
+ points[3] = (GdkPoint){xdir*(-topright_div_2), height}; /* bottomleft */
+ }
+ else
+ {
+ points[0] = (GdkPoint){height, xdir*(topright - stripe_width - topright_div_2)}; /* topleft */
+ points[1] = (GdkPoint){height, xdir*(topright - topright_div_2)}; /* topright */
+ points[2] = (GdkPoint){0, xdir*(stripe_width - topright_div_2)}; /* bottomright */
+ points[3] = (GdkPoint){0, xdir*(-topright_div_2)}; /* bottomleft */
+ }
+
+
+ shift = (stripe_width*2)/(double)10;
+ cl_progressbar_points_transform (points, 4, (offset*shift), is_horizontal);
+
+ trans = (width/2)-1-(stripe_width*2);
+ cl_progressbar_points_transform (points, 4, trans, is_horizontal);
+ gdk_draw_polygon (tmp, clearlooks_style->spot2_gc, TRUE, points, 4);
+ cl_progressbar_points_transform (points, 4, -trans, is_horizontal);
+
+ trans = width/2-1;
+ cl_progressbar_points_transform (points, 4, trans, is_horizontal);
+ gdk_draw_polygon (tmp, clearlooks_style->spot2_gc, TRUE, points, 4);
+ cl_progressbar_points_transform (points, 4, -trans, is_horizontal);
+
+ trans = (width/2)-1+(stripe_width*2);
+ cl_progressbar_points_transform (points, 4, trans, is_horizontal);
+ gdk_draw_polygon (tmp, clearlooks_style->spot2_gc, TRUE, points, 4);
+
+ return tmp;
+}
+
+/* could be improved, I think. */
+void cl_progressbar_fill (GdkDrawable *drawable, GtkWidget *widget,
+ GtkStyle *style, GdkGC *gc,
+ gint x, gint y,
+ gint width, gint height,
+ guint8 offset, GdkRectangle *area)
+{
+ GtkProgressBarOrientation orientation = gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (widget));
+ gint size = (orientation == GTK_PROGRESS_LEFT_TO_RIGHT || orientation == GTK_PROGRESS_RIGHT_TO_LEFT) ? height : width;
+ GdkPixmap *tile = cl_progressbar_tile_new (widget->window, widget, style, size, offset);
+
+ gint nx = x,
+ ny = y,
+ nwidth = height,
+ nheight = width;
+
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ switch (orientation)
+ {
+ case GTK_PROGRESS_LEFT_TO_RIGHT:
+ {
+ while (nx <= x + width )
+ {
+ if (nx + nwidth > x+width ) nwidth = (x+width) - nx;
+ gdk_draw_drawable (drawable, gc, tile, 0, 0, nx, y, nwidth, height);
+ if (height <= 1)
+ nx += 1;
+ else
+ nx += (height-1 + !(height % 2));
+ }
+ break;
+ }
+ case GTK_PROGRESS_RIGHT_TO_LEFT:
+ {
+ gint src_x = 0, dst_x;
+ nx += width;
+ while (nx >= x )
+ {
+ dst_x = nx - height;
+ if (dst_x < x )
+ {
+ src_x = x - dst_x;
+ dst_x = x;
+ }
+ gdk_draw_drawable (drawable, gc, tile, src_x, 0, dst_x, y, nwidth, height);
+ if (height <= 1)
+ nx -= 1;
+ else
+ nx -= (height-1 + !(height % 2));
+ }
+ break;
+ }
+ case GTK_PROGRESS_TOP_TO_BOTTOM:
+ {
+ while (ny <= y + height )
+ {
+ if (ny + nheight > y+height ) nheight = (y+height) - ny;
+ gdk_draw_drawable (drawable, gc, tile, 0, 0, x, ny, width, nheight);
+ if (width <= 1)
+ ny += 1;
+ else
+ ny += (width-1 + !(width % 2));
+ }
+ break;
+ }
+ case GTK_PROGRESS_BOTTOM_TO_TOP:
+ {
+ gint src_y = 0, dst_y;
+ ny += height;
+ while (ny >= y )
+ {
+ dst_y = ny - width;
+ if (dst_y < y )
+ {
+ src_y = y - dst_y;
+ dst_y = y;
+ }
+ gdk_draw_drawable (drawable, gc, tile, 0, src_y, x, dst_y, width, width);
+ if (width <= 1)
+ ny -= 1;
+ else
+ ny -= (width-1 + !(width % 2));
+ }
+ break;
+ }
+ }
+
+ gdk_gc_set_clip_rectangle (gc, NULL);
+
+ g_object_unref (tile);
+}
+
+GdkColor cl_gc_set_fg_color_shade (GdkGC *gc, GdkColormap *colormap,
+ GdkColor *from, gfloat s)
+{
+ GdkColor tmp_color;
+ GdkGCValues values;
+
+ shade (from, &tmp_color, s);
+ gdk_gc_get_values (gc, &values);
+ gdk_rgb_find_color (colormap, &tmp_color);
+ gdk_gc_set_foreground (gc, &tmp_color);
+
+ return values.foreground;
+}
+
+/* #warning MOVE THIS TO SUPPORT.C/H SO THE DRAW_CORNER FUNCTION CAN USE IT. OR, MAKE DRAW_CORNER USE IT SOME OTHER WAY. */
+
+static void cl_get_window_style_state (GtkWidget *widget, GtkStyle **style, GtkStateType *state_type)
+{
+ GtkStyle *windowstyle = NULL;
+ GtkWidget *tmpwidget = widget;
+ GtkStateType windowstate;
+
+ if (widget && GTK_IS_ENTRY (widget))
+ tmpwidget = tmpwidget->parent;
+
+ while (tmpwidget && GTK_WIDGET_NO_WINDOW (tmpwidget) && !GTK_IS_NOTEBOOK(tmpwidget))
+ {
+ tmpwidget = tmpwidget->parent;
+ }
+
+ *style = tmpwidget->style;
+ *state_type = GTK_WIDGET_STATE(tmpwidget);
+}
+
+static GdkGC *cl_get_window_bg_gc (GtkWidget *widget)
+{
+ GtkStyle *style;
+ GtkStateType state_type;
+
+ cl_get_window_style_state (widget, &style, &state_type);
+
+ return style->bg_gc[state_type];
+}
+
+/******************************************************************************
+ * DRAW THE MIGHTY WIDGETS! *
+ ******************************************************************************/
+
+void cl_draw_inset (GtkStyle *style, GdkWindow *window, GtkWidget *widget,
+ GdkRectangle *area,
+ gint x, gint y, gint width, gint height,
+ int tl, int tr, int bl, int br )
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE(style);
+ ClearlooksStyle *clwindowstyle; /* style of the window this widget is on */
+ GtkStateType windowstate;
+ CLRectangle r;
+
+ cl_rectangle_init (&r, NULL, style->black_gc,
+ tl, tr, bl, br);
+
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+
+ cl_get_window_style_state(widget, (GtkStyle**)&clwindowstyle, &windowstate);
+
+ g_assert (clwindowstyle != NULL);
+
+ if (GTK_WIDGET_HAS_DEFAULT (widget))
+ {
+ r.bordergc = style->mid_gc[GTK_STATE_NORMAL];
+ }
+ else
+ {
+ cl_rectangle_set_gradient (&r.border_gradient,
+ &clwindowstyle->inset_dark[windowstate],
+ &clwindowstyle->inset_light[windowstate]);
+ }
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+/* Draw a normal (toggle)button. Not spinbuttons.*/
+void cl_draw_button(GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE(style);
+ int my_state_type = (state_type == GTK_STATE_ACTIVE) ? 2 : 0;
+ GdkGC *bg_gc = NULL;
+ gboolean is_active = FALSE;
+ CLRectangle r;
+
+ /* Get the background color of the window we're on */
+ bg_gc = cl_get_window_bg_gc(widget);
+
+ cl_rectangle_set_button (&r, style, state_type,
+ GTK_WIDGET_HAS_DEFAULT (widget),
+ GTK_WIDGET_HAS_FOCUS (widget),
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+
+ if (state_type == GTK_STATE_ACTIVE)
+ is_active = TRUE;
+
+ if (GTK_IS_TOGGLE_BUTTON(widget) &&
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) &&
+ state_type == GTK_STATE_PRELIGHT)
+ {
+ cl_rectangle_set_gradient (&r.fill_gradient, &clearlooks_style->shade[1], &clearlooks_style->shade[1]);
+ r.topleft = clearlooks_style->shade_gc[3];
+ r.bottomright = clearlooks_style->shade_gc[1];
+
+ is_active = TRUE;
+ }
+
+ if (!is_active)
+ r.fillgc = NULL;
+
+ if (!GTK_IS_NOTEBOOK (widget->parent))
+ {
+ gdk_draw_rectangle (window, bg_gc, FALSE, x, y, width-1, height-1);
+
+ /* Draw "sunken" look when border thickness is more than 2 pixels. */
+ if (style->xthickness > 2 && style->ythickness > 2)
+ cl_draw_inset (style, window, widget, area, x, y, width, height,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+ }
+
+ /* Draw "sunken" look when border thickness is more than 2 pixels.*/
+ if (style->xthickness > 2 && style->ythickness > 2)
+ {
+ x++;
+ y++;
+ height-=2;
+ width-=2;
+ }
+
+ /* Don't draw the normal gradient for normal buttons. */
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+
+
+ if (!is_active)
+ {
+ int tmp_height = (float)height*0.25;
+
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2,y+2,width-4,tmp_height,
+ &clearlooks_style->button_g1[state_type],
+ &clearlooks_style->button_g2[state_type]);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2, y+2+tmp_height, width-4, height-3-tmp_height*2,
+ &clearlooks_style->button_g2[state_type],
+ &clearlooks_style->button_g3[state_type]);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2,y+height-tmp_height-1,width-4,tmp_height,
+ &clearlooks_style->button_g3[state_type],
+ &clearlooks_style->button_g4[state_type]);
+
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL);
+ }
+
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+/* Draw spinbuttons. */
+void cl_draw_spinbutton(GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ CLRectangle r;
+ GdkRectangle new_area;
+
+ int tl = CL_CORNER_NONE, tr = CL_CORNER_NONE,
+ bl = CL_CORNER_NONE, br = CL_CORNER_NONE;
+
+ if (area == NULL)
+ {
+ new_area.x = x;
+ new_area.y = y;
+ new_area.width = width;
+ new_area.height = height;
+ area = &new_area;
+ }
+
+ if (!strcmp (detail, "spinbutton")) /* draws the 'back' of the spinbutton */
+ {
+ GdkGC *bg_gc = cl_get_window_bg_gc(widget);
+
+ gdk_gc_set_clip_rectangle (bg_gc, area);
+ gdk_draw_rectangle (window, bg_gc, FALSE, x, y, width-1, height-1);
+ gdk_gc_set_clip_rectangle (bg_gc, NULL);
+
+ if (style->xthickness > 2 && style->ythickness > 2)
+ cl_draw_inset (style, window, widget, area, x, y, width, height,
+ CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+
+ return;
+ }
+
+ if (!strcmp (detail, "spinbutton_up"))
+ {
+ tr = CL_CORNER_ROUND;
+
+ (style->xthickness > 2 && style->ythickness > 2) ? y++ : height++;
+ }
+
+ if (!strcmp (detail, "spinbutton_down"))
+ {
+ br = CL_CORNER_ROUND;
+
+ if (style->xthickness > 2 && style->ythickness > 2)
+ height--;
+ }
+
+ cl_rectangle_set_button (&r, style, state_type,
+ GTK_WIDGET_HAS_DEFAULT (widget),
+ GTK_WIDGET_HAS_FOCUS (widget),
+ tl, tr,
+ bl, br);
+ width--;
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+void cl_draw_combobox_entry (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ CLRectangle r;
+
+ gboolean rtl = get_direction (widget->parent) == GTK_TEXT_DIR_RTL;
+ gboolean has_focus = GTK_WIDGET_HAS_FOCUS (widget);
+
+ int cl = rtl ? CL_CORNER_NONE : CL_CORNER_ROUND,
+ cr = rtl ? CL_CORNER_ROUND : CL_CORNER_NONE;
+
+ GdkGC *bg_gc = cl_get_window_bg_gc(widget);
+
+ if (rtl)
+ {
+ if (!has_focus)
+ {
+ x -= 1;
+ width +=1;
+ }
+ }
+ else
+ {
+ width += 2;
+ if (has_focus) width--; /* this gives us a 2px focus line at the right side. */
+ }
+
+ cl_rectangle_set_entry (&r, style, state_type,
+ cl, cr, cl, cr,
+ has_focus);
+
+ gdk_gc_set_clip_rectangle (bg_gc, area);
+ gdk_draw_rectangle (window, bg_gc, FALSE, x, y, width-1, height-1);
+ gdk_gc_set_clip_rectangle (bg_gc, NULL);
+
+ /* Draw "sunken" look when border thickness is more than 2 pixels. */
+ if (style->xthickness > 2 && style->ythickness > 2)
+ {
+ cl_draw_inset (style, window, widget, area, x, y, width, height,
+ cl, cr, cl, cr);
+
+ y++;
+ x++;
+ width-=2;
+ height-=2;
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+void cl_draw_combobox_button (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE(style);
+ gboolean is_active = FALSE;
+ gboolean draw_inset = FALSE;
+ CLRectangle r;
+
+ cl_rectangle_set_button (&r, style, state_type,
+ GTK_WIDGET_HAS_DEFAULT (widget),
+ GTK_WIDGET_HAS_FOCUS (widget),
+ CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+
+ if (state_type == GTK_STATE_ACTIVE)
+ is_active = TRUE;
+ else
+ r.fillgc = NULL;
+
+ /* Seriously, why can't non-gtk-apps at least try to be decent citizens?
+ Take this fscking OpenOffice.org 1.9 for example. The morons responsible
+ for this utter piece of crap give the clip size wrong values! :'( */
+
+ if (area)
+ {
+ area->x = x;
+ area->y = y;
+ area->width = width;
+ area->height = height;
+ }
+
+ x--;
+ width++;
+
+ /* Draw "sunken" look when border thickness is more than 2 pixels. */
+ if (GTK_IS_COMBO(widget->parent))
+ draw_inset = (widget->parent->style->xthickness > 2 &&
+ widget->parent->style->ythickness > 2);
+ else
+ draw_inset = (style->xthickness > 2 && style->ythickness > 2);
+
+ if (draw_inset)
+ {
+ cl_draw_inset (style, window, widget, area, x, y, width, height,
+ CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+
+ x++;
+ y++;
+ height-=2;
+ width-=2;
+ }
+ else
+ {
+ x++;
+ width--;
+ }
+
+ if (area)
+ cl_rectangle_set_clip_rectangle (&r, area);
+
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+
+ if (!is_active)
+ {
+ int tmp_height = (float)height*0.25;
+
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2,y+2,width-4,tmp_height,
+ &clearlooks_style->button_g1[state_type],
+ &clearlooks_style->button_g2[state_type]);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2, y+2+tmp_height, width-4, height-3-tmp_height*2,
+ &clearlooks_style->button_g2[state_type],
+ &clearlooks_style->button_g3[state_type]);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x+2,y+height-tmp_height-1,width-4,tmp_height,
+ &clearlooks_style->button_g3[state_type],
+ &clearlooks_style->button_g4[state_type]);
+
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL);
+ }
+
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+
+ if (area)
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+/* Draw text Entry */
+void cl_draw_entry (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ CLRectangle r;
+ gboolean has_focus = GTK_WIDGET_HAS_FOCUS(widget);
+ GdkGC *bg_gc = cl_get_window_bg_gc(widget);
+
+ gdk_draw_rectangle (window, bg_gc, FALSE, x, y, width-1, height-1);
+
+ gtk_style_apply_default_background (style, window, TRUE, state_type,
+ area, x+1, y+1, width-2, height-2);
+
+
+ cl_rectangle_set_entry (&r, style, state_type,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ has_focus);
+
+ /* Draw "sunken" look when border thickness is more than 2 pixels. */
+ if (style->xthickness > 2 && style->ythickness > 2)
+ {
+ cl_draw_inset (style, window, widget, area, x, y, width, height,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+
+ x++;
+ y++;
+ width-=2;
+ height-=2;
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+}
+
+void cl_draw_optionmenu(GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area, GtkWidget *widget,
+ const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE(style);
+ GtkRequisition indicator_size;
+ GtkBorder indicator_spacing;
+ int line_pos;
+
+ option_menu_get_props (widget, &indicator_size, &indicator_spacing);
+
+ if (get_direction (widget) == GTK_TEXT_DIR_RTL)
+ line_pos = x + (indicator_size.width + indicator_spacing.left + indicator_spacing.right) + style->xthickness;
+ else
+ line_pos = x + width - (indicator_size.width + indicator_spacing.left + indicator_spacing.right) - style->xthickness;
+
+ cl_draw_button (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[3],
+ line_pos, y + style->ythickness - 1, line_pos,
+ y + height - style->ythickness);
+
+ gdk_draw_line (window, style->light_gc[state_type],
+ line_pos+1, y + style->ythickness - 1, line_pos+1,
+ y + height - style->ythickness);
+}
+
+
+void cl_draw_menuitem_button (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ ClearlooksStyle *clearlooks_style = (ClearlooksStyle*)style;
+ gboolean menubar = (widget->parent && GTK_IS_MENU_BAR(widget->parent)) ? TRUE : FALSE;
+ int corner = CL_CORNER_NARROW;
+ GdkColor lower_color;
+
+ shade (&style->base[GTK_STATE_SELECTED], &lower_color, 0.85);
+
+ if (menubar)
+ {
+ height++;
+ corner = CL_CORNER_NONE;
+ r->bordergc = clearlooks_style->border_gc[CL_BORDER_UPPER];
+ }
+ else
+ {
+ r->bordergc = clearlooks_style->spot3_gc;
+ }
+
+ cl_rectangle_set_corners (r, corner, corner, corner, corner);
+
+ cl_rectangle_set_gradient (&r->fill_gradient,
+ &style->base[GTK_STATE_SELECTED], &lower_color);
+
+ r->gradient_type = CL_GRADIENT_VERTICAL;
+
+ r->fillgc = clearlooks_style->spot2_gc;
+ r->topleft = clearlooks_style->spot1_gc;
+
+ cl_rectangle_set_clip_rectangle (r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, r);
+ cl_rectangle_reset_clip_rectangle (r);
+}
+
+void cl_draw_menuitem_flat (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ ClearlooksStyle *clearlooks_style = (ClearlooksStyle*)style;
+ gboolean menubar = (widget->parent && GTK_IS_MENU_BAR(widget->parent)) ? TRUE : FALSE;
+ GdkColor tmp;
+
+ cl_rectangle_set_corners (r, CL_CORNER_NARROW, CL_CORNER_NARROW,
+ CL_CORNER_NARROW, CL_CORNER_NARROW);
+
+ tmp = cl_gc_set_fg_color_shade (style->black_gc, style->colormap,
+ &style->base[GTK_STATE_PRELIGHT], 0.8);
+
+ r->bordergc = style->black_gc;
+ r->fillgc = style->base_gc[GTK_STATE_PRELIGHT];
+
+ if (menubar) height++;
+
+ cl_rectangle_set_clip_rectangle (r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, r);
+ cl_rectangle_reset_clip_rectangle (r);
+
+ gdk_gc_set_foreground (style->black_gc, &tmp);
+}
+
+void cl_draw_menuitem_gradient (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int width, int height, CLRectangle *r)
+{
+ ClearlooksStyle *clearlooks_style = (ClearlooksStyle*)style;
+ gboolean menubar = (widget->parent && GTK_IS_MENU_BAR(widget->parent)) ? TRUE : FALSE;
+ GdkColor tmp;
+ GdkColor lower_color;
+
+ shade (&style->base[GTK_STATE_SELECTED], &lower_color, 0.8);
+
+ cl_rectangle_set_corners (r, CL_CORNER_NARROW, CL_CORNER_NARROW,
+ CL_CORNER_NARROW, CL_CORNER_NARROW);
+
+ cl_rectangle_set_gradient (&r->fill_gradient,
+ &style->base[GTK_STATE_SELECTED], &lower_color);
+
+ r->gradient_type = CL_GRADIENT_VERTICAL;
+
+ tmp = cl_gc_set_fg_color_shade (style->black_gc, style->colormap,
+ &style->base[GTK_STATE_PRELIGHT], 0.8);
+
+ r->bordergc = style->black_gc;
+ r->fillgc = style->base_gc[GTK_STATE_PRELIGHT];
+
+ if (menubar) height++;
+
+ cl_rectangle_set_clip_rectangle (r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, r);
+ cl_rectangle_reset_clip_rectangle (r);
+
+ gdk_gc_set_foreground (style->black_gc, &tmp);
+}
+
+void cl_draw_treeview_header (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ gint columns = 0, column_index = -1, fill_width = width;
+ gboolean is_etree = strcmp("ETree", G_OBJECT_TYPE_NAME(widget->parent)) == 0;
+ gboolean resizable = TRUE;
+
+ GdkGC *bottom = clearlooks_style->shade_gc[5];
+
+ if ( width < 2 || height < 2 )
+ return;
+
+ if (GTK_IS_TREE_VIEW (widget->parent))
+ {
+ gtk_treeview_get_header_index (GTK_TREE_VIEW(widget->parent),
+ widget, &column_index, &columns,
+ &resizable);
+ }
+ else if (GTK_IS_CLIST (widget->parent))
+ {
+ gtk_clist_get_header_index (GTK_CLIST(widget->parent),
+ widget, &column_index, &columns);
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], area);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[4], area);
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[5], area);
+ }
+
+ if (state_type != GTK_STATE_NORMAL)
+ fill_width-=2;
+
+ gdk_draw_rectangle (window, style->bg_gc[state_type], TRUE, x, y, fill_width, height-(height/3)+1);
+
+ draw_hgradient (window, style->bg_gc[state_type], style,
+ x, 1+y+height-(height/3), fill_width, height/3,
+ &style->bg[state_type], &clearlooks_style->inset_dark[state_type]);
+
+ if (resizable || (column_index != columns-1))
+ {
+ gdk_draw_line (window, clearlooks_style->shade_gc[4], x+width-2, y+4, x+width-2, y+height-5);
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x+width-1, y+4, x+width-1, y+height-5);
+ }
+
+ /* left light line */
+ if (column_index == 0)
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x, y+1, x, y+height-2);
+
+ /* top light line */
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x, y, x+width-1, y);
+
+ /* bottom dark line */
+ if (state_type == GTK_STATE_INSENSITIVE)
+ bottom = clearlooks_style->shade_gc[3];
+
+
+ gdk_draw_line (window, bottom, x, y+height-1, x+width-1, y+height-1);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], NULL);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[4], NULL);
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[5], NULL);
+ }
+}
diff --git a/libs/clearlooks/clearlooks_draw.h b/libs/clearlooks/clearlooks_draw.h
new file mode 100644
index 0000000000..a8cbb3732f
--- /dev/null
+++ b/libs/clearlooks/clearlooks_draw.h
@@ -0,0 +1,159 @@
+#ifndef CLEARLOOKS_DRAW_H
+#define CLEARLOOKS_DRAW_H
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+typedef struct
+{
+ GdkColor *from;
+ GdkColor *to;
+} CLGradient;
+
+typedef enum
+{
+ CL_GRADIENT_NONE,
+ CL_GRADIENT_HORIZONTAL,
+ CL_GRADIENT_VERTICAL
+} CLGradientType;
+
+typedef struct
+{
+ CLGradient fill_gradient;
+ CLGradient border_gradient;
+
+ CLGradientType gradient_type;
+
+ GdkGC *bordergc;
+ GdkGC *fillgc;
+
+ guint8 corners[4];
+
+ GdkGC *topleft; /* top + left shadow */
+ GdkGC *bottomright; /* bottom + right shadow */
+
+ GdkColor tmp_color; /* used for gradient */
+} CLRectangle;
+
+typedef enum /* DON'T CHANGE THE ORDER! */
+{
+ CL_CORNER_TOPRIGHT,
+ CL_CORNER_BOTTOMRIGHT,
+ CL_CORNER_BOTTOMLEFT,
+ CL_CORNER_TOPLEFT
+} CLCornerSide;
+
+typedef enum /* DON'T CHANGE THE ORDER! */
+{
+ CL_BORDER_TOP,
+ CL_BORDER_RIGHT,
+ CL_BORDER_BOTTOM,
+ CL_BORDER_LEFT
+} CLBorderType;
+
+typedef enum
+{
+ CL_CORNER_NONE = 0,
+ CL_CORNER_NARROW = 1,
+ CL_CORNER_ROUND = 2
+} CLCornerSharpness;
+
+
+
+CLRectangle *cl_rectangle_new(GdkGC *fillgc, GdkGC *bordergc,
+ int tl, int tr, int bl, int br);
+
+void cl_draw_rectangle (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r);
+
+void cl_rectangle_set_color (CLGradient *g, GdkColor *color);
+void cl_rectangle_set_gradient (CLGradient *g, GdkColor *from, GdkColor *to);
+
+void cl_rectangle_set_button (CLRectangle *r, GtkStyle *style,
+ GtkStateType state_type, gboolean hasdefault, gboolean has_focus,
+ CLBorderType tl, CLBorderType tr,
+ CLBorderType bl, CLBorderType br);
+
+void cl_rectangle_set_entry (CLRectangle *r, GtkStyle *style,
+ GtkStateType state_type,
+ CLBorderType tl, CLBorderType tr,
+ CLBorderType bl, CLBorderType br,
+ gboolean has_focus);
+
+void cl_draw_shadow(GdkWindow *window, GtkWidget *widget, GtkStyle *style,
+ int x, int y, int width, int height, CLRectangle *r);
+
+void cl_rectangle_set_clip_rectangle (CLRectangle *r, GdkRectangle *area);
+void cl_rectangle_reset_clip_rectangle (CLRectangle *r);
+
+void cl_set_corner_sharpness (const gchar *detail, GtkWidget *widget, CLRectangle *r);
+
+
+void cl_rectangle_set_corners (CLRectangle *r, int tl, int tr, int bl, int br);
+
+void cl_rectangle_init (CLRectangle *r, GdkGC *fillgc, GdkGC *bordergc,
+ int tl, int tr, int bl, int br);
+
+void cl_rectangle_reset (CLRectangle *r, GtkStyle *style);
+
+
+GdkPixmap* cl_progressbar_tile_new (GdkDrawable *drawable, GtkWidget *widget,
+ GtkStyle *style, gint height, gint offset);
+
+void cl_progressbar_fill (GdkDrawable *drawable, GtkWidget *widget,
+ GtkStyle *style, GdkGC *gc,
+ gint x, gint y, gint width, gint height,
+ guint8 offset, GdkRectangle *area);
+
+GdkColor cl_gc_set_fg_color_shade (GdkGC *gc, GdkColormap *colormap,
+ GdkColor *from, gfloat s);
+
+void cl_draw_spinbutton(GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+void cl_draw_button(GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+void cl_draw_entry (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+void cl_draw_combobox_entry (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+void cl_draw_combobox_button (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+void cl_draw_menuitem_button (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int wiidth, int height, CLRectangle *r);
+
+void cl_draw_menuitem_flat (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int wiidth, int height, CLRectangle *r);
+
+void cl_draw_menuitem_gradient (GdkDrawable *window, GtkWidget *widget, GtkStyle *style,
+ GdkRectangle *area, GtkStateType state_type,
+ int x, int y, int wiidth, int height, CLRectangle *r);
+
+void cl_draw_treeview_header (GtkStyle *style, GdkWindow *window,
+ GtkStateType state_type, GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget, const gchar *detail,
+ gint x, gint y, gint width, gint height);
+
+#endif /* CLEARLOOKS_DRAW_H */
diff --git a/libs/clearlooks/clearlooks_rc_style.c b/libs/clearlooks/clearlooks_rc_style.c
new file mode 100644
index 0000000000..1c5f2c495e
--- /dev/null
+++ b/libs/clearlooks/clearlooks_rc_style.c
@@ -0,0 +1,392 @@
+/* Clearlooks theme engine
+ * Copyright (C) 2005 Richard Stellingwerff.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>
+ * and by Alexander Larsson <alexl@redhat.com>
+ * Modified by Richard Stellingwerff <remenic@gmail.com>
+ */
+
+#include "clearlooks_style.h"
+#include "clearlooks_rc_style.h"
+
+static void clearlooks_rc_style_init (ClearlooksRcStyle *style);
+static void clearlooks_rc_style_class_init (ClearlooksRcStyleClass *klass);
+static GtkStyle *clearlooks_rc_style_create_style (GtkRcStyle *rc_style);
+static guint clearlooks_rc_style_parse (GtkRcStyle *rc_style,
+ GtkSettings *settings,
+ GScanner *scanner);
+static void clearlooks_rc_style_merge (GtkRcStyle *dest,
+ GtkRcStyle *src);
+
+
+static GtkRcStyleClass *parent_class;
+
+GType clearlooks_type_rc_style = 0;
+
+enum
+{
+ TOKEN_SPOTCOLOR = G_TOKEN_LAST + 1,
+ TOKEN_CONTRAST,
+ TOKEN_SUNKENMENU,
+ TOKEN_PROGRESSBARSTYLE,
+ TOKEN_MENUBARSTYLE,
+ TOKEN_MENUITEMSTYLE,
+ TOKEN_LISTVIEWITEMSTYLE
+};
+
+static struct
+ {
+ const gchar *name;
+ guint token;
+ }
+theme_symbols[] =
+{
+ { "spotcolor", TOKEN_SPOTCOLOR },
+ { "contrast", TOKEN_CONTRAST },
+ { "sunkenmenubar", TOKEN_SUNKENMENU },
+ { "progressbarstyle", TOKEN_PROGRESSBARSTYLE },
+ { "menubarstyle", TOKEN_MENUBARSTYLE },
+ { "menuitemstyle", TOKEN_MENUITEMSTYLE },
+ { "listviewitemstyle", TOKEN_LISTVIEWITEMSTYLE }
+};
+
+
+void
+clearlooks_rc_style_register_type (GTypeModule *module)
+{
+ static const GTypeInfo object_info =
+ {
+ sizeof (ClearlooksRcStyleClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) clearlooks_rc_style_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ClearlooksRcStyle),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) clearlooks_rc_style_init,
+ NULL
+ };
+
+ clearlooks_type_rc_style = g_type_module_register_type (module,
+ GTK_TYPE_RC_STYLE,
+ "ClearlooksRcStyle",
+ &object_info, 0);
+}
+
+static void
+clearlooks_rc_style_init (ClearlooksRcStyle *clearlooks_rc)
+{
+ clearlooks_rc->has_spot_color = FALSE;
+ clearlooks_rc->contrast = 1.0;
+ clearlooks_rc->sunkenmenubar = 1;
+ clearlooks_rc->progressbarstyle = 0;
+ clearlooks_rc->menubarstyle = 0;
+ clearlooks_rc->menuitemstyle = 1;
+ clearlooks_rc->listviewitemstyle = 1;
+}
+
+static void
+clearlooks_rc_style_class_init (ClearlooksRcStyleClass *klass)
+{
+ GtkRcStyleClass *rc_style_class = GTK_RC_STYLE_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ rc_style_class->parse = clearlooks_rc_style_parse;
+ rc_style_class->create_style = clearlooks_rc_style_create_style;
+ rc_style_class->merge = clearlooks_rc_style_merge;
+}
+
+static guint
+theme_parse_color(GtkSettings *settings,
+ GScanner *scanner,
+ GdkColor *color)
+{
+ guint token;
+
+ /* Skip 'blah_color' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ return gtk_rc_parse_color (scanner, color);
+}
+
+static guint
+theme_parse_contrast(GtkSettings *settings,
+ GScanner *scanner,
+ double *contrast)
+{
+ guint token;
+
+ /* Skip 'contrast' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_FLOAT)
+ return G_TOKEN_FLOAT;
+
+ *contrast = scanner->value.v_float;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_sunkenmenubar(GtkSettings *settings,
+ GScanner *scanner,
+ guint8 *sunken)
+{
+ guint token;
+
+ /* Skip 'sunkenmenubar' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ *sunken = scanner->value.v_int;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_progressbarstyle(GtkSettings *settings,
+ GScanner *scanner,
+ guint8 *progressbarstyle)
+{
+ guint token;
+
+ /* Skip 'sunkenmenubar' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ *progressbarstyle = scanner->value.v_int;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_menubarstyle(GtkSettings *settings,
+ GScanner *scanner,
+ guint8 *menubarstyle)
+{
+ guint token;
+
+ /* Skip 'menubarstyle' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ *menubarstyle = scanner->value.v_int;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_menuitemstyle(GtkSettings *settings,
+ GScanner *scanner,
+ guint8 *menuitemstyle)
+{
+ guint token;
+
+ /* Skip 'sunkenmenubar' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ *menuitemstyle = scanner->value.v_int;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_listviewitemstyle(GtkSettings *settings,
+ GScanner *scanner,
+ guint8 *listviewitemstyle)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ *listviewitemstyle = scanner->value.v_int;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+clearlooks_rc_style_parse (GtkRcStyle *rc_style,
+ GtkSettings *settings,
+ GScanner *scanner)
+
+{
+ static GQuark scope_id = 0;
+ ClearlooksRcStyle *clearlooks_style = CLEARLOOKS_RC_STYLE (rc_style);
+
+ guint old_scope;
+ guint token;
+ guint i;
+
+ /* Set up a new scope in this scanner. */
+
+ if (!scope_id)
+ scope_id = g_quark_from_string("clearlooks_theme_engine");
+
+ /* If we bail out due to errors, we *don't* reset the scope, so the
+ * error messaging code can make sense of our tokens.
+ */
+ old_scope = g_scanner_set_scope(scanner, scope_id);
+
+ /* Now check if we already added our symbols to this scope
+ * (in some previous call to clearlooks_rc_style_parse for the
+ * same scanner.
+ */
+
+ if (!g_scanner_lookup_symbol(scanner, theme_symbols[0].name))
+ {
+ g_scanner_freeze_symbol_table(scanner);
+ for (i = 0; i < G_N_ELEMENTS (theme_symbols); i++)
+ g_scanner_scope_add_symbol(scanner, scope_id,
+ theme_symbols[i].name,
+ GINT_TO_POINTER(theme_symbols[i].token));
+ g_scanner_thaw_symbol_table(scanner);
+ }
+
+ /* We're ready to go, now parse the top level */
+
+ token = g_scanner_peek_next_token(scanner);
+ while (token != G_TOKEN_RIGHT_CURLY)
+ {
+ switch (token)
+ {
+ case TOKEN_SPOTCOLOR:
+ token = theme_parse_color(settings, scanner, &clearlooks_style->spot_color);
+ clearlooks_style->has_spot_color = TRUE;
+ break;
+ case TOKEN_CONTRAST:
+ token = theme_parse_contrast(settings, scanner, &clearlooks_style->contrast);
+ break;
+ case TOKEN_SUNKENMENU:
+ token = theme_parse_sunkenmenubar(settings, scanner, &clearlooks_style->sunkenmenubar);
+ break;
+ case TOKEN_PROGRESSBARSTYLE:
+ token = theme_parse_progressbarstyle(settings, scanner, &clearlooks_style->progressbarstyle);
+ break;
+ case TOKEN_MENUBARSTYLE:
+ token = theme_parse_menubarstyle(settings, scanner, &clearlooks_style->menubarstyle);
+ break;
+ case TOKEN_MENUITEMSTYLE:
+ token = theme_parse_menuitemstyle(settings, scanner, &clearlooks_style->menuitemstyle);
+ break;
+ case TOKEN_LISTVIEWITEMSTYLE:
+ token = theme_parse_listviewitemstyle(settings, scanner, &clearlooks_style->listviewitemstyle);
+ break;
+ default:
+ g_scanner_get_next_token(scanner);
+ token = G_TOKEN_RIGHT_CURLY;
+ break;
+ }
+
+ if (token != G_TOKEN_NONE)
+ return token;
+
+ token = g_scanner_peek_next_token(scanner);
+ }
+
+ g_scanner_get_next_token(scanner);
+
+ g_scanner_set_scope(scanner, old_scope);
+
+ return G_TOKEN_NONE;
+}
+
+static void
+clearlooks_rc_style_merge (GtkRcStyle *dest,
+ GtkRcStyle *src)
+{
+ ClearlooksRcStyle *dest_w, *src_w;
+
+ parent_class->merge (dest, src);
+
+ if (!CLEARLOOKS_IS_RC_STYLE (src))
+ return;
+
+ src_w = CLEARLOOKS_RC_STYLE (src);
+ dest_w = CLEARLOOKS_RC_STYLE (dest);
+
+ dest_w->contrast = src_w->contrast;
+ dest_w->sunkenmenubar = src_w->sunkenmenubar;
+ dest_w->progressbarstyle = src_w->progressbarstyle;
+ dest_w->menubarstyle = src_w->menubarstyle;
+ dest_w->menuitemstyle = src_w->menuitemstyle;
+ dest_w->listviewitemstyle = src_w->listviewitemstyle;
+
+ if (src_w->has_spot_color)
+ {
+ dest_w->has_spot_color = TRUE;
+ dest_w->spot_color = src_w->spot_color;
+ }
+}
+
+
+/* Create an empty style suitable to this RC style
+ */
+static GtkStyle *
+clearlooks_rc_style_create_style (GtkRcStyle *rc_style)
+{
+ return GTK_STYLE (g_object_new (CLEARLOOKS_TYPE_STYLE, NULL));
+}
diff --git a/libs/clearlooks/clearlooks_rc_style.h b/libs/clearlooks/clearlooks_rc_style.h
new file mode 100644
index 0000000000..bd8e0ca05d
--- /dev/null
+++ b/libs/clearlooks/clearlooks_rc_style.h
@@ -0,0 +1,57 @@
+/* Clearlooks Theme Engine
+ * Copyright (C) 2005 Richard Stellingwerff.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>
+ * and by Alexander Larsson <alexl@redhat.com>
+ * Modified by Richard Stellingwerff <remenic@gmail.com>
+ */
+
+#include <gtk/gtkrc.h>
+
+typedef struct _ClearlooksRcStyle ClearlooksRcStyle;
+typedef struct _ClearlooksRcStyleClass ClearlooksRcStyleClass;
+
+extern GType clearlooks_type_rc_style;
+
+#define CLEARLOOKS_TYPE_RC_STYLE clearlooks_type_rc_style
+#define CLEARLOOKS_RC_STYLE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), CLEARLOOKS_TYPE_RC_STYLE, ClearlooksRcStyle))
+#define CLEARLOOKS_RC_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLEARLOOKS_TYPE_RC_STYLE, ClearlooksRcStyleClass))
+#define CLEARLOOKS_IS_RC_STYLE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), CLEARLOOKS_TYPE_RC_STYLE))
+#define CLEARLOOKS_IS_RC_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLEARLOOKS_TYPE_RC_STYLE))
+#define CLEARLOOKS_RC_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLEARLOOKS_TYPE_RC_STYLE, ClearlooksRcStyleClass))
+
+struct _ClearlooksRcStyle
+{
+ GtkRcStyle parent_instance;
+
+ GdkColor spot_color;
+ gboolean has_spot_color;
+ double contrast;
+ guint8 sunkenmenubar;
+ guint8 progressbarstyle;
+ guint8 menubarstyle;
+ guint8 menuitemstyle;
+ guint8 listviewitemstyle;
+};
+
+struct _ClearlooksRcStyleClass
+{
+ GtkRcStyleClass parent_class;
+};
+
+void clearlooks_rc_style_register_type (GTypeModule *module);
diff --git a/libs/clearlooks/clearlooks_style.c b/libs/clearlooks/clearlooks_style.c
new file mode 100644
index 0000000000..241f14c6e4
--- /dev/null
+++ b/libs/clearlooks/clearlooks_style.c
@@ -0,0 +1,2657 @@
+#include <gtk/gtk.h>
+
+#include "clearlooks_style.h"
+#include "clearlooks_rc_style.h"
+#include "clearlooks_draw.h"
+
+#include <math.h>
+#include <string.h>
+
+#include "bits.c"
+#include "support.h"
+//#include "config.h"
+
+/* #define DEBUG 1 */
+
+#define SCALE_SIZE 5
+
+#define DETAIL(xx) ((detail) && (!strcmp(xx, detail)))
+#define COMPARE_COLORS(a,b) (a.red == b.red && a.green == b.green && a.blue == b.blue)
+
+#define DRAW_ARGS GtkStyle *style, \
+ GdkWindow *window, \
+ GtkStateType state_type, \
+ GtkShadowType shadow_type, \
+ GdkRectangle *area, \
+ GtkWidget *widget, \
+ const gchar *detail, \
+ gint x, \
+ gint y, \
+ gint width, \
+ gint height
+
+static GdkGC *realize_color (GtkStyle * style, GdkColor * color);
+static GtkStyleClass *parent_class;
+static GList *progressbars = NULL;
+static gint8 pboffset = 10;
+static int timer_id = 0;
+
+static void cl_progressbar_remove (gpointer data)
+{
+ if (g_list_find (progressbars, data) == NULL)
+ return;
+
+ progressbars = g_list_remove (progressbars, data);
+ g_object_unref (data);
+
+ if (g_list_first(progressbars) == NULL) {
+ g_source_remove(timer_id);
+ timer_id = 0;
+ }
+}
+
+static void update_progressbar (gpointer data, gpointer user_data)
+{
+ gfloat fraction;
+
+ if (data == NULL)
+ return;
+
+ fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (data));
+
+ /* update only if not filled */
+ if (fraction < 1.0)
+ gtk_widget_queue_resize ((GtkWidget*)data);
+
+ if (fraction >= 1.0 || GTK_PROGRESS (data)->activity_mode)
+ cl_progressbar_remove (data);
+}
+
+static gboolean timer_func (gpointer data)
+{
+ g_list_foreach (progressbars, update_progressbar, NULL);
+ if (--pboffset < 0) pboffset = 9;
+ return (g_list_first(progressbars) != NULL);
+}
+
+static gboolean cl_progressbar_known(gconstpointer data)
+{
+ return (g_list_find (progressbars, data) != NULL);
+}
+
+
+static void cl_progressbar_add (gpointer data)
+{
+ if (!GTK_IS_PROGRESS_BAR (data))
+ return;
+
+ progressbars = g_list_append (progressbars, data);
+
+ g_object_ref (data);
+ g_signal_connect ((GObject*)data, "unrealize", G_CALLBACK (cl_progressbar_remove), data);
+
+ if (timer_id == 0)
+ timer_id = g_timeout_add (100, timer_func, NULL);
+}
+
+static GdkColor *
+clearlooks_get_spot_color (ClearlooksRcStyle *clearlooks_rc)
+{
+ GtkRcStyle *rc = GTK_RC_STYLE (clearlooks_rc);
+
+ if (clearlooks_rc->has_spot_color)
+ return &clearlooks_rc->spot_color;
+ else
+ return &rc->base[GTK_STATE_SELECTED];
+}
+
+/**************************************************************************/
+
+/* used for optionmenus... */
+static void
+draw_tab (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ GtkShadowType shadow_type,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+#define ARROW_SPACE 2
+#define ARROW_LINE_HEIGHT 2
+#define ARROW_LINE_WIDTH 5
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GtkRequisition indicator_size;
+ GtkBorder indicator_spacing;
+ gint arrow_height;
+
+ option_menu_get_props (widget, &indicator_size, &indicator_spacing);
+
+ indicator_size.width += (indicator_size.width % 2) - 1;
+ arrow_height = indicator_size.width / 2 + 2;
+
+ x += (width - indicator_size.width) / 2;
+ y += height/2;
+
+ if (state_type == GTK_STATE_INSENSITIVE)
+ {
+ draw_arrow (window, style->light_gc[state_type], area,
+ GTK_ARROW_UP, 1+x, 1+y-arrow_height,
+ indicator_size.width, arrow_height);
+
+ draw_arrow (window, style->light_gc[state_type], area,
+ GTK_ARROW_DOWN, 1+x, 1+y+1,
+ indicator_size.width, arrow_height);
+ }
+
+ draw_arrow (window, style->fg_gc[state_type], area,
+ GTK_ARROW_UP, x, y-arrow_height,
+ indicator_size.width, arrow_height);
+
+ draw_arrow (window, style->fg_gc[state_type], area,
+ GTK_ARROW_DOWN, x, y+1,
+ indicator_size.width, arrow_height);
+}
+
+static void
+clearlooks_draw_arrow (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ GtkArrowType arrow_type,
+ gboolean fill,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ gint original_width, original_x;
+ GdkGC *gc;
+
+ sanitize_size (window, &width, &height);
+
+ if (is_combo_box (widget))
+ {
+ width = 7;
+ height = 5;
+ x+=2;
+ y+=4;
+ if (state == GTK_STATE_INSENSITIVE)
+ {
+ draw_arrow (window, style->light_gc[state], area,
+ GTK_ARROW_UP, 1+x, 1+y-height,
+ width, height);
+
+ draw_arrow (window, style->light_gc[state], area,
+ GTK_ARROW_DOWN, 1+x, 1+y+1,
+ width, height);
+ }
+
+ draw_arrow (window, style->fg_gc[state], area,
+ GTK_ARROW_UP, x, y-height,
+ width, height);
+
+ draw_arrow (window, style->fg_gc[state], area,
+ GTK_ARROW_DOWN, x, y+1,
+ width, height);
+
+ return;
+ }
+
+ original_width = width;
+ original_x = x;
+
+ /* Make spinbutton arrows and arrows in menus
+ * slightly larger to get the right pixels drawn */
+ if (DETAIL ("spinbutton"))
+ height += 1;
+
+ if (DETAIL("menuitem"))
+ {
+ width = 6;
+ height = 7;
+ }
+
+ /* Compensate arrow position for "sunken" look */
+ if (DETAIL ("spinbutton") && arrow_type == GTK_ARROW_DOWN &&
+ style->xthickness > 2 && style->ythickness > 2)
+ y -= 1;
+
+ if (widget && widget->parent && GTK_IS_COMBO (widget->parent->parent))
+ {
+ width -= 2;
+ height -=2;
+ x++;
+ }
+
+ calculate_arrow_geometry (arrow_type, &x, &y, &width, &height);
+
+ if (DETAIL ("menuitem"))
+ x = original_x + original_width - width;
+
+ if (DETAIL ("spinbutton") && (arrow_type == GTK_ARROW_DOWN))
+ y += 1;
+
+ if (state == GTK_STATE_INSENSITIVE)
+ draw_arrow (window, style->light_gc[state], area, arrow_type, x + 1, y + 1, width, height);
+
+ gc = style->fg_gc[state];
+
+ draw_arrow (window, gc, area, arrow_type, x, y, width, height);
+}
+
+
+static void
+draw_flat_box (DRAW_ARGS)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ if (detail &&
+ clearlooks_style->listviewitemstyle == 1 &&
+ state_type == GTK_STATE_SELECTED && (
+ !strncmp ("cell_even", detail, strlen ("cell_even")) ||
+ !strncmp ("cell_odd", detail, strlen ("cell_odd"))))
+ {
+ GdkGC *gc;
+ GdkColor lower_color;
+ GdkColor *upper_color;
+
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ {
+ gc = style->base_gc[state_type];
+ upper_color = &style->base[state_type];
+ }
+ else
+ {
+ gc = style->base_gc[GTK_STATE_ACTIVE];
+ upper_color = &style->base[GTK_STATE_ACTIVE];
+ }
+
+ if (GTK_IS_TREE_VIEW (widget) && 0)
+ {
+ GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+ if (gtk_tree_selection_count_selected_rows (sel) > 1)
+ {
+ parent_class->draw_flat_box (style, window, state_type, shadow_type,
+ area, widget, detail,
+ x, y, width, height);
+ return;
+ }
+ }
+
+ shade (upper_color, &lower_color, 0.8);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ draw_hgradient (window, gc, style,
+ x, y, width, height, upper_color, &lower_color);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+ }
+ else
+ {
+ parent_class->draw_flat_box (style, window, state_type,
+ shadow_type,
+ area, widget, detail,
+ x, y, width, height);
+ }
+}
+/**************************************************************************/
+
+static void
+draw_shadow (DRAW_ARGS)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ CLRectangle r;
+
+ GdkGC *outer_gc = clearlooks_style->shade_gc[4];
+ GdkGC *gc1 = NULL;
+ GdkGC *gc2 = NULL;
+ gint thickness_light;
+ gint thickness_dark;
+ gboolean interior_focus = FALSE;
+
+#if DEBUG
+ printf("draw_shadow: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ if (widget == NULL)
+ {
+ gdk_draw_rectangle (window, outer_gc, FALSE,
+ x, y, width - 1, height - 1);
+ return;
+ }
+
+ if ((width == -1) && (height == -1))
+ gdk_window_get_size (window, &width, &height);
+ else if (width == -1)
+ gdk_window_get_size (window, &width, NULL);
+ else if (height == -1)
+ gdk_window_get_size (window, NULL, &height);
+
+ cl_rectangle_reset (&r, style);
+
+ if (DETAIL ("frame") && widget->parent &&
+ GTK_IS_STATUSBAR (widget->parent))
+ {
+ gtk_style_apply_default_background (style, window,widget && !GTK_WIDGET_NO_WINDOW (widget),
+ state_type, area, x, y, width, height);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], area);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], area);
+ }
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[3],
+ x, y, x + width, y);
+ gdk_draw_line (window, clearlooks_style->shade_gc[0],
+ x, y + 1, x + width, y + 1);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], NULL);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], NULL);
+ }
+ }
+ else if (detail && !strcmp (detail, "entry"))
+ {
+ if ( widget->parent && (GTK_IS_COMBO_BOX_ENTRY (widget->parent) ||
+ GTK_IS_SPIN_BUTTON(widget) ||
+ GTK_IS_COMBO (widget->parent)))
+ {
+ cl_draw_combobox_entry (style, window, GTK_WIDGET_STATE(widget), shadow_type, area, widget, detail, x, y, width, height);
+ }
+ else
+ {
+ cl_draw_entry (style, window, GTK_WIDGET_STATE(widget), shadow_type, area, widget, detail, x, y, width, height);
+ }
+ }
+ else if (DETAIL ("viewport") || DETAIL ("scrolled_window"))
+ {
+ gdk_draw_rectangle (window, clearlooks_style->shade_gc[4], FALSE,
+ x, y, width - 1, height - 1);
+ }
+ else
+ {
+ if (DETAIL ("menuitem"))
+ outer_gc = clearlooks_style->spot3_gc;
+ else
+ outer_gc = clearlooks_style->shade_gc[4];
+
+ if (shadow_type == GTK_SHADOW_IN)
+ gdk_draw_rectangle (window, outer_gc, FALSE,
+ x, y, width - 1, height - 1);
+ else if (shadow_type == GTK_SHADOW_OUT)
+ {
+ gdk_draw_rectangle (window, outer_gc, FALSE,
+ x, y, width - 1, height - 1);
+ gdk_draw_line (window, style->light_gc[state_type],
+ x+1, y+1, x+width-2, y+1);
+ gdk_draw_line (window, style->light_gc[state_type],
+ x+1, y+1, x+1, y+height-2);
+ }
+ else if (shadow_type == GTK_SHADOW_ETCHED_IN)
+ {
+ GdkGC *a = clearlooks_style->shade_gc[(shadow_type == GTK_SHADOW_ETCHED_IN) ? 0 : 3];
+ GdkGC *b = clearlooks_style->shade_gc[(shadow_type == GTK_SHADOW_ETCHED_IN) ? 3 : 0];
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.bordergc = a;
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x+1, y+1, width-1, height-1, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ r.bordergc = b;
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width-1, height-1, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (shadow_type == GTK_SHADOW_ETCHED_IN)
+ {
+ GdkGC *a = clearlooks_style->shade_gc[(shadow_type == GTK_SHADOW_ETCHED_IN) ? 3 : 0];
+ GdkGC *b = clearlooks_style->shade_gc[(shadow_type == GTK_SHADOW_ETCHED_IN) ? 0 : 3];
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.bordergc = a;
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x+1, y+1, width-1, height-1, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ r.bordergc = b;
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width-1, height-1, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else
+ parent_class->draw_shadow (style, window, state_type, shadow_type,
+ area, widget, detail,
+ x, y, width, height);
+ }
+}
+
+#define GDK_RECTANGLE_SET(rect,a,b,c,d) rect.x = a; \
+ rect.y = b; \
+ rect.width = c; \
+ rect.height = d;
+
+
+static void
+draw_box_gap (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gint gap_x,
+ gint gap_width)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ CLRectangle r;
+
+ GdkRegion *area_region = NULL,
+ *gap_region = NULL;
+ GdkRectangle light_rect;
+ GdkRectangle dark_rect;
+
+#if DEBUG
+ printf("draw_box_gap: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ cl_rectangle_reset (&r, style);
+
+ r.bordergc = clearlooks_style->shade_gc[5];
+
+ r.topleft = style->light_gc[state_type];
+ r.bottomright = clearlooks_style->shade_gc[1];
+
+ if (area)
+ area_region = gdk_region_rectangle (area);
+ else
+ {
+ GdkRectangle tmp = { x, y, width, height };
+ area_region = gdk_region_rectangle (&tmp);
+ }
+
+ switch (gap_side)
+ {
+ case GTK_POS_TOP:
+ {
+ GdkRectangle rect = { x+gap_x+1, y, gap_width-2, 2 };
+ gap_region = gdk_region_rectangle (&rect);
+
+ GDK_RECTANGLE_SET (light_rect, x+gap_x+1, y, x+gap_x+1, y+1);
+ GDK_RECTANGLE_SET (dark_rect, x+gap_x+gap_width-2, y, x+gap_x+gap_width-2, y);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+
+ break;
+ }
+ case GTK_POS_BOTTOM:
+ {
+ GdkRectangle rect = { x+gap_x+1, y+height-2, gap_width-2, 2 };
+ gap_region = gdk_region_rectangle (&rect);
+
+ GDK_RECTANGLE_SET (light_rect, x+gap_x+1, y+height-2, x+gap_x+1, y+height-1);
+ GDK_RECTANGLE_SET (dark_rect, x+gap_x+gap_width-2, y+height-2, x+gap_x+gap_width-2, y+height-1);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ break;
+ }
+ case GTK_POS_LEFT:
+ {
+ GdkRectangle rect = { x, y+gap_x+1, 2, gap_width-2 };
+ gap_region = gdk_region_rectangle (&rect);
+
+ GDK_RECTANGLE_SET (light_rect, x, y+gap_x+1, x+1, y+gap_x+1);
+ GDK_RECTANGLE_SET (dark_rect, x, y+gap_x+gap_width-2, x, y+gap_x+gap_width-2);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+ break;
+ }
+ case GTK_POS_RIGHT:
+ {
+ GdkRectangle rect = { x+width-2, y+gap_x+1, 2, gap_width-2 };
+ gap_region = gdk_region_rectangle (&rect);
+
+ GDK_RECTANGLE_SET (light_rect, x+width-2, y+gap_x+1, x+width-1, y+gap_x+1);
+ GDK_RECTANGLE_SET (dark_rect, x+width-2, y+gap_x+gap_width-2, x+width-1, y+gap_x+gap_width-2);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_NONE);
+ break;
+ }
+ }
+
+ gdk_region_subtract (area_region, gap_region);
+
+ gdk_gc_set_clip_region (r.bordergc, area_region);
+ gdk_gc_set_clip_region (r.topleft, area_region);
+ gdk_gc_set_clip_region (r.bottomright, area_region);
+
+ gdk_region_destroy (area_region);
+ gdk_region_destroy (gap_region);
+
+ gdk_draw_rectangle (window, style->bg_gc[state_type], TRUE, x, y, width, height);
+
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+
+ gdk_gc_set_clip_region (r.bordergc, NULL);
+ gdk_gc_set_clip_region (r.topleft, NULL);
+ gdk_gc_set_clip_region (r.bottomright, NULL);
+
+ /* it's a semi hack */
+ gdk_draw_line (window, style->light_gc[state_type],
+ light_rect.x, light_rect.y,
+ light_rect.width, light_rect.height);
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[1],
+ dark_rect.x, dark_rect.y,
+ dark_rect.width, dark_rect.height);
+}
+
+/**************************************************************************/
+
+static void
+draw_extension (DRAW_ARGS, GtkPositionType gap_side)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int my_state_type = (state_type == GTK_STATE_ACTIVE) ? 2 : 0;
+ CLRectangle r;
+
+#if DEBUG
+ printf("draw_extension: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ if (DETAIL ("tab"))
+ {
+ GdkRectangle new_area;
+ GdkColor tmp_color;
+
+ cl_rectangle_set_button (&r, style, state_type, FALSE, FALSE,
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+
+ if (state_type == GTK_STATE_ACTIVE)
+ shade (&style->bg[state_type], &tmp_color, 1.08);
+ else
+ shade (&style->bg[state_type], &tmp_color, 1.05);
+
+ if (area)
+ {
+ new_area = *area;
+ }
+ else
+ {
+ new_area.x = x;
+ new_area.y = y;
+ new_area.width = width;
+ new_area.height = height;
+ }
+
+ switch (gap_side)
+ {
+ case GTK_POS_BOTTOM:
+ height+=2;
+ new_area.y = y;
+ new_area.height = height-2;
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+ cl_rectangle_set_gradient (&r.fill_gradient, &tmp_color, &style->bg[state_type]);
+ cl_rectangle_set_gradient (&r.border_gradient,
+ &clearlooks_style->border[CL_BORDER_UPPER+my_state_type],
+ &clearlooks_style->border[CL_BORDER_LOWER+my_state_type]);
+ break;
+ case GTK_POS_TOP:
+ y-=2;
+ height+=2;
+ new_area.y = y+2;
+ new_area.height = height;
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+ cl_rectangle_set_gradient (&r.fill_gradient, &style->bg[state_type], &tmp_color);
+ cl_rectangle_set_gradient (&r.border_gradient,
+ &clearlooks_style->border[CL_BORDER_LOWER+my_state_type],
+ &clearlooks_style->border[CL_BORDER_UPPER+my_state_type]);
+ break;
+ case GTK_POS_LEFT:
+ x-=2;
+ width+=2;
+ new_area.x = x+2;
+ new_area.width = width;
+ r.gradient_type = CL_GRADIENT_HORIZONTAL;
+ cl_rectangle_set_gradient (&r.fill_gradient, &style->bg[state_type], &tmp_color);
+ cl_rectangle_set_gradient (&r.border_gradient,
+ &clearlooks_style->border[CL_BORDER_LOWER+my_state_type],
+ &clearlooks_style->border[CL_BORDER_UPPER+my_state_type]);
+ break;
+ case GTK_POS_RIGHT:
+ width+=2;
+ new_area.x = x;
+ new_area.width = width-2;
+ r.gradient_type = CL_GRADIENT_HORIZONTAL;
+ cl_rectangle_set_gradient (&r.fill_gradient, &tmp_color, &style->bg[state_type]);
+ cl_rectangle_set_gradient (&r.border_gradient,
+ &clearlooks_style->border[CL_BORDER_UPPER+my_state_type],
+ &clearlooks_style->border[CL_BORDER_LOWER+my_state_type]);
+ break;
+ }
+
+ r.topleft = style->light_gc[state_type];
+ r.bottomright = (state_type == GTK_STATE_NORMAL) ? clearlooks_style->shade_gc[1] : NULL;
+
+ cl_rectangle_set_clip_rectangle (&r, &new_area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ /* draw the selection stripe */
+ if (state_type != GTK_STATE_ACTIVE) {
+ cl_rectangle_set_gradient (&r.fill_gradient, NULL, NULL);
+ r.fillgc = clearlooks_style->spot2_gc;
+
+ switch (gap_side)
+ {
+ case GTK_POS_BOTTOM:
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+ cl_rectangle_set_gradient (&r.border_gradient, &clearlooks_style->spot3, &clearlooks_style->spot2);
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+
+ cl_rectangle_set_clip_rectangle (&r, &new_area);
+ cl_draw_rectangle (window, widget, style, x, y, width, 3, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ break;
+ case GTK_POS_TOP:
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+ cl_rectangle_set_gradient (&r.border_gradient, &clearlooks_style->spot2, &clearlooks_style->spot3);
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+
+ cl_rectangle_set_clip_rectangle (&r, &new_area);
+ cl_draw_rectangle (window, widget, style, x, y + height - 3, width, 3, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ break;
+ case GTK_POS_LEFT:
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+ cl_rectangle_set_gradient (&r.border_gradient, &clearlooks_style->spot2, &clearlooks_style->spot3);
+ r.gradient_type = CL_GRADIENT_HORIZONTAL;
+
+ cl_rectangle_set_clip_rectangle (&r, &new_area);
+ cl_draw_rectangle (window, widget, style, x + width - 3, y, 3, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ break;
+ case GTK_POS_RIGHT:
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_NONE);
+ cl_rectangle_set_gradient (&r.border_gradient, &clearlooks_style->spot3, &clearlooks_style->spot2);
+ r.gradient_type = CL_GRADIENT_HORIZONTAL;
+
+ cl_rectangle_set_clip_rectangle (&r, &new_area);
+ cl_draw_rectangle (window, widget, style, x, y, 3, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ break;
+ }
+ }
+
+
+ }
+ else
+ {
+ parent_class->draw_extension (style, window, state_type, shadow_type, area,
+ widget, detail, x, y, width, height,
+ gap_side);
+ }
+}
+
+
+/**************************************************************************/
+
+static void
+draw_handle (DRAW_ARGS, GtkOrientation orientation)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ gint xx, yy;
+ gint xthick, ythick;
+ GdkGC *light_gc, *dark_gc;
+ GdkRectangle rect;
+ GdkRectangle dest;
+ gint intersect;
+ gint h;
+ int i;
+ int n_lines;
+ int offset;
+
+#if DEBUG
+ printf("draw_handle: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ if (state_type == GTK_STATE_PRELIGHT)
+ gtk_style_apply_default_background (style, window,
+ widget && !GTK_WIDGET_NO_WINDOW (widget),
+ state_type, area, x, y, width, height);
+
+ /* orientation is totally bugged, but this actually works... */
+ orientation = (width > height) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+
+ if (!strcmp (detail, "paned"))
+ {
+ /* we want to ignore the shadow border in paned widgets */
+ xthick = 0;
+ ythick = 0;
+ }
+ else
+ {
+ xthick = style->xthickness;
+ ythick = style->ythickness;
+ }
+
+ if ( ((DETAIL ("handlebox") && widget && GTK_IS_HANDLE_BOX (widget)) || DETAIL ("dockitem")) &&
+ orientation == GTK_ORIENTATION_VERTICAL )
+ {
+ /* The line in the toolbar */
+
+ light_gc = style->light_gc[state_type];
+ dark_gc = clearlooks_style->shade_gc[3];
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (light_gc, area);
+ gdk_gc_set_clip_rectangle (dark_gc, area);
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (light_gc, NULL);
+ gdk_gc_set_clip_rectangle (dark_gc, NULL);
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], area);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], area);
+ }
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x, y, x + width, y);
+ gdk_draw_line (window, clearlooks_style->shade_gc[3], x, y + height - 1, x + width, y + height - 1);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], NULL);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], NULL);
+ }
+ }
+
+ light_gc = clearlooks_style->shade_gc[0];
+ dark_gc = clearlooks_style->shade_gc[4];
+
+ rect.x = x + xthick;
+ rect.y = y + ythick;
+ rect.width = width - (xthick * 2);
+ rect.height = height - (ythick * 2);
+
+ if (area)
+ intersect = gdk_rectangle_intersect (area, &rect, &dest);
+ else
+ {
+ intersect = TRUE;
+ dest = rect;
+ }
+
+ if (!intersect)
+ return;
+
+ gdk_gc_set_clip_rectangle (light_gc, &dest);
+ gdk_gc_set_clip_rectangle (dark_gc, &dest);
+
+ n_lines = (!strcmp (detail, "paned")) ? 21 : 11;
+
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ h = width - 2 * xthick;
+ h = MAX (3, h - 6);
+
+ xx = x + (width - h) / 2;
+ offset = (height - 2*ythick - 2*n_lines)/2 + 1;
+ if (offset < 0)
+ offset = 0;
+
+ for (i = 0, yy = y + ythick + offset; yy <= (y + height - ythick - 1) && i < n_lines; yy += 2, i++)
+ {
+ gdk_draw_line (window, dark_gc, xx, yy, xx + h, yy);
+ gdk_draw_line (window, light_gc, xx, yy + 1, xx + h, yy + 1);
+ }
+ }
+ else
+ {
+ h = height - 2 * ythick;
+ h = MAX (3, h - 6);
+
+ yy = y + (height - h) / 2;
+ offset = (width - 2*xthick - 2*n_lines)/2 + 1;
+ if (offset < 0)
+ offset = 0;
+
+ for (i = 0, xx = x + xthick + offset; i < n_lines; xx += 2, i++)
+ {
+ gdk_draw_line (window, dark_gc, xx, yy, xx, yy + h);
+ gdk_draw_line (window, light_gc, xx + 1, yy, xx + 1, yy + h);
+ }
+ }
+
+ gdk_gc_set_clip_rectangle (light_gc, NULL);
+ gdk_gc_set_clip_rectangle (dark_gc, NULL);
+}
+
+/**************************************************************************/
+
+static void
+draw_box (DRAW_ARGS)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ CLRectangle r;
+ gboolean false_size = FALSE;
+
+#ifdef DEBUG
+ printf("draw_box: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (style != NULL);
+ g_return_if_fail (window != NULL);
+
+ if (width == -1 || height == -1)
+ false_size = TRUE;
+
+ if ((width == -1) && (height == -1))
+ gdk_window_get_size (window, &width, &height);
+ else if (width == -1)
+ gdk_window_get_size (window, &width, NULL);
+ else if (height == -1)
+ gdk_window_get_size (window, NULL, &height);
+
+ cl_rectangle_reset (&r, style);
+
+ if (widget == NULL)
+ return;
+
+ /* listview headers */
+ if (widget && DETAIL ("button") && widget->parent &&
+ (GTK_IS_TREE_VIEW(widget->parent) ||
+ GTK_IS_CLIST (widget->parent) ||
+ strcmp(G_OBJECT_TYPE_NAME (widget->parent), "ETree") == 0))
+ {
+ cl_draw_treeview_header (style, window, state_type, shadow_type,
+ area, widget, detail, x, y, width, height);
+ }
+ else if (detail && (!strcmp (detail, "button") ||
+ !strcmp (detail, "buttondefault")))
+ {
+ if (GTK_IS_COMBO_BOX_ENTRY(widget->parent) || GTK_IS_COMBO(widget->parent))
+ {
+ cl_draw_combobox_button (style, window, state_type, shadow_type,
+ area, widget,
+ detail, x, y, width, height);
+ }
+ else
+ {
+ cl_draw_button (style, window, state_type, shadow_type, area, widget,
+ detail, x, y, width, height);
+ }
+ }
+ else if (detail && (
+ !strcmp (detail, "spinbutton_up") ||
+ !strcmp (detail, "spinbutton_down") ||
+ !strcmp (detail, "spinbutton")))
+ {
+ cl_draw_spinbutton (style, window, state_type, shadow_type, area,
+ widget, detail, x, y, width, height);
+ }
+ else if (detail && (
+ !strcmp (detail, "hscale") || !strcmp (detail, "vscale")))
+ {
+ cl_rectangle_set_button (&r, style, state_type,
+ GTK_WIDGET_HAS_DEFAULT (widget), GTK_WIDGET_HAS_FOCUS (widget),
+ CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+
+ if (!strcmp (detail, "hscale") || !strcmp (detail, "vscale"))
+ {
+ r.fill_gradient.to = &clearlooks_style->shade[2];
+ r.bottomright = clearlooks_style->shade_gc[2];
+ }
+
+ cl_set_corner_sharpness (detail, widget, &r);
+
+ if (!strcmp (detail, "spinbutton_up"))
+ {
+ r.border_gradient.to = r.border_gradient.from;
+ height++;
+ gtk_style_apply_default_background (style, window, FALSE, state_type,
+ area, x, y, width, height);
+ }
+ else if (!strcmp (detail, "spinbutton_down"))
+ {
+ r.border_gradient.to = r.border_gradient.from;
+ gtk_style_apply_default_background (style, window, FALSE, state_type,
+ area, x, y, width, height);
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x+1, y+1, width-2, height-2, &r);
+ cl_draw_shadow (window, widget, style, x+1, y+1, width-2, height-2, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (DETAIL ("trough") && GTK_IS_PROGRESS_BAR (widget))
+ {
+ GdkPoint points[4] = { {x,y}, {x+width-1,y}, {x,y+height-1}, {x+width-1,y+height-1} };
+
+ gdk_draw_points (window, style->bg_gc[state_type], points, 4);
+
+ r.bordergc = clearlooks_style->shade_gc[5];
+ r.fillgc = clearlooks_style->shade_gc[2];
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NARROW, CL_CORNER_NARROW,
+ CL_CORNER_NARROW, CL_CORNER_NARROW);
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (DETAIL ("trough") &&
+ (GTK_IS_VSCALE (widget) || GTK_IS_HSCALE (widget)))
+ {
+ GdkGC *inner = clearlooks_style->shade_gc[3],
+ *outer = clearlooks_style->shade_gc[5],
+ *shadow = clearlooks_style->shade_gc[4];
+ GdkColor upper_color = *clearlooks_get_spot_color (CLEARLOOKS_RC_STYLE (style->rc_style)),
+ lower_color;
+
+ GtkAdjustment *adjustment = gtk_range_get_adjustment (GTK_RANGE (widget));
+
+ GtkOrientation orientation = GTK_RANGE (widget)->orientation;
+
+ gint fill_size = (orientation ? height : width) *
+ (1 / ((adjustment->upper - adjustment->lower) /
+ (adjustment->value - adjustment->lower)));
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ y += (height - SCALE_SIZE) / 2;
+ height = SCALE_SIZE;
+ }
+ else
+ {
+ x += (width - SCALE_SIZE) / 2;
+ width = SCALE_SIZE;
+ }
+
+ if (state_type == GTK_STATE_INSENSITIVE)
+ {
+ outer = clearlooks_style->shade_gc[4];
+ inner = clearlooks_style->shade_gc[2];
+ shadow = clearlooks_style->shade_gc[3];
+ }
+
+ cl_rectangle_init (&r, inner, outer, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE );
+
+ r.topleft = shadow;
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ /* DRAW FILL */
+ shade (&upper_color, &lower_color, 1.3);
+
+ r.bordergc = clearlooks_style->spot3_gc;
+ r.fillgc = style->bg_gc[state_type];
+
+ r.gradient_type = (orientation == GTK_ORIENTATION_HORIZONTAL ) ? CL_GRADIENT_VERTICAL
+ : CL_GRADIENT_HORIZONTAL;
+
+ cl_rectangle_set_gradient (&r.fill_gradient, &upper_color, &lower_color);
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ if (orientation == GTK_ORIENTATION_HORIZONTAL && fill_size > 1)
+ {
+ if (gtk_range_get_inverted(GTK_RANGE(widget)) != (get_direction(widget) == GTK_TEXT_DIR_RTL))
+ cl_draw_rectangle (window, widget, style, x+width-fill_size, y, fill_size, height, &r);
+ else
+ cl_draw_rectangle (window, widget, style, x, y, fill_size, height, &r);
+ }
+ else if (fill_size > 1)
+ {
+ if (gtk_range_get_inverted (GTK_RANGE (widget)))
+ cl_draw_rectangle (window, widget, style, x, y+height-fill_size, width, fill_size, &r);
+ else
+ cl_draw_rectangle (window, widget, style, x, y, width, fill_size, &r);
+ }
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (DETAIL ("trough"))
+ {
+ GdkGC *inner = clearlooks_style->shade_gc[3],
+ *outer = clearlooks_style->shade_gc[5];
+
+ cl_rectangle_init (&r, inner, outer, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE );
+
+ if (GTK_RANGE (widget)->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ y+=1;
+ height-=2;
+ }
+ else
+ {
+ x+=1;
+ width-=2;
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (detail && (!strcmp (detail, "vscrollbar") ||
+ !strcmp (detail, "hscrollbar") ||
+ !strcmp (detail, "stepper")))
+ {
+ ClScrollButtonType button_type = CL_SCROLLBUTTON_OTHER;
+ gboolean horizontal = TRUE;
+
+ if (GTK_IS_VSCROLLBAR(widget))
+ {
+ if (y == widget->allocation.y)
+ button_type = CL_SCROLLBUTTON_BEGIN;
+ else if (y+height == widget->allocation.y+widget->allocation.height)
+ button_type = CL_SCROLLBUTTON_END;
+
+ horizontal = FALSE;
+ }
+ else if (GTK_IS_HSCROLLBAR(widget))
+ {
+ if (x == widget->allocation.x)
+ button_type = CL_SCROLLBUTTON_BEGIN;
+ else if (x+width == widget->allocation.x+widget->allocation.width)
+ button_type = CL_SCROLLBUTTON_END;
+ }
+
+ cl_rectangle_set_button (&r, style, state_type, FALSE, FALSE, 0,0,0,0);
+
+ cl_rectangle_set_gradient (&r.fill_gradient, NULL, NULL);
+ cl_rectangle_set_gradient (&r.fill_gradient, &clearlooks_style->inset_light[state_type],
+ &clearlooks_style->inset_dark[state_type]);
+
+
+ r.gradient_type = horizontal ? CL_GRADIENT_VERTICAL
+ : CL_GRADIENT_HORIZONTAL;
+
+ r.bottomright = clearlooks_style->shade_gc[1];
+ r.border_gradient.to = r.border_gradient.from;
+
+ if (button_type == CL_SCROLLBUTTON_OTHER)
+ {
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+ }
+ else if (button_type == CL_SCROLLBUTTON_BEGIN)
+ {
+ if (horizontal)
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_NONE);
+ else
+ cl_rectangle_set_corners (&r, CL_CORNER_ROUND, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+ }
+ else
+ {
+ if (horizontal)
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_ROUND,
+ CL_CORNER_NONE, CL_CORNER_ROUND);
+ else
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_ROUND, CL_CORNER_ROUND);
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ }
+ else if (DETAIL ("slider"))
+ {
+ if (DETAIL("slider") && widget && GTK_IS_RANGE (widget))
+ {
+ GtkAdjustment *adj = GTK_RANGE (widget)->adjustment;
+
+ if (adj->value <= adj->lower &&
+ (GTK_RANGE (widget)->has_stepper_a || GTK_RANGE (widget)->has_stepper_b))
+ {
+ if (GTK_IS_VSCROLLBAR (widget))
+ {
+ y-=1;
+ height+=1;
+ }
+ else if (GTK_IS_HSCROLLBAR (widget))
+ {
+ x-=1;
+ width+=1;
+ }
+ }
+ if (adj->value >= adj->upper - adj->page_size &&
+ (GTK_RANGE (widget)->has_stepper_c || GTK_RANGE (widget)->has_stepper_d))
+ {
+ if (GTK_IS_VSCROLLBAR (widget))
+ height+=1;
+ else if (GTK_IS_HSCROLLBAR (widget))
+ width+=1;
+ }
+ }
+
+ cl_rectangle_set_button (&r, style, state_type, FALSE, GTK_WIDGET_HAS_FOCUS (widget),
+ CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.gradient_type = GTK_IS_HSCROLLBAR (widget) ? CL_GRADIENT_VERTICAL
+ : CL_GRADIENT_HORIZONTAL;
+
+ cl_rectangle_set_gradient (&r.fill_gradient, &clearlooks_style->inset_light[state_type],
+ &clearlooks_style->inset_dark[state_type]);
+
+ r.bottomright = clearlooks_style->shade_gc[1];
+ r.border_gradient.to = r.border_gradient.from;
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (detail && !strcmp (detail, "optionmenu")) /* supporting deprecated */
+ {
+ cl_draw_optionmenu(style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
+ }
+ else if (DETAIL ("menuitem"))
+ {
+ if (clearlooks_style->menuitemstyle == 0)
+ {
+ cl_draw_menuitem_flat (window, widget, style, area, state_type,
+ x, y, width, height, &r);
+ }
+ else if (clearlooks_style->menuitemstyle == 1)
+ {
+ cl_draw_menuitem_gradient (window, widget, style, area, state_type,
+ x, y, width, height, &r);
+ }
+ else
+ {
+ cl_draw_menuitem_button (window, widget, style, area, state_type,
+ x, y, width, height, &r);
+ }
+ }
+ else if (DETAIL ("menubar") && (clearlooks_style->sunkenmenubar || clearlooks_style->menubarstyle > 0))
+ {
+ GdkGC *dark = clearlooks_style->shade_gc[2];
+ GdkColor upper_color, lower_color;
+
+ /* don't draw sunken menubar on gnome panel
+ IT'S A HACK! HORRIBLE HACK! HIDEOUS HACK!
+ BUT IT WORKS FOR ME(tm)! */
+ if (widget->parent &&
+ strcmp(G_OBJECT_TYPE_NAME (widget->parent), "PanelWidget") == 0)
+ return;
+
+ shade(&style->bg[state_type], &upper_color, 1.0);
+ shade(&style->bg[state_type], &lower_color, 0.95);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.fillgc = style->bg_gc[state_type];
+ r.bordergc = clearlooks_style->shade_gc[2];
+ r.gradient_type = CL_GRADIENT_VERTICAL;
+
+ cl_rectangle_set_gradient (&r.border_gradient, &clearlooks_style->shade[2],
+ &clearlooks_style->shade[3]);
+ cl_rectangle_set_gradient (&r.fill_gradient, &upper_color, &lower_color);
+
+ /* make vertical and top borders invisible for style 2 */
+ if (clearlooks_style->menubarstyle == 2) {
+ x--; width+=2;
+ y--; height+=1;
+ }
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+ }
+ else if (DETAIL ("menu") && widget->parent &&
+ GDK_IS_WINDOW (widget->parent->window))
+ {
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.bordergc = clearlooks_style->border_gc[CL_BORDER_UPPER];
+ r.topleft = style->light_gc[state_type];
+ r.bottomright = clearlooks_style->shade_gc[1];
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ return;
+ }
+ else if (DETAIL ("bar") && widget && GTK_IS_PROGRESS_BAR (widget))
+ {
+ GdkColor upper_color = *clearlooks_get_spot_color (CLEARLOOKS_RC_STYLE (style->rc_style)),
+ lower_color,
+ prev_foreground;
+ gboolean activity_mode = GTK_PROGRESS (widget)->activity_mode;
+
+#ifdef HAVE_ANIMATION
+ if (!activity_mode && gtk_progress_bar_get_fraction (widget) != 1.0 &&
+ !cl_progressbar_known((gconstpointer)widget))
+ {
+ cl_progressbar_add ((gpointer)widget);
+ }
+#endif
+ cl_progressbar_fill (window, widget, style, style->black_gc,
+ x, y, width, height,
+#ifdef HAVE_ANIMATION
+ activity_mode ? 0 : pboffset,
+#else
+ 0,
+#endif
+ area);
+
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ r.bordergc = clearlooks_style->spot3_gc;
+ r.topleft = clearlooks_style->spot2_gc;
+
+ prev_foreground = cl_gc_set_fg_color_shade (clearlooks_style->spot2_gc,
+ style->colormap,
+ &clearlooks_style->spot2,
+ 1.2);
+
+ cl_rectangle_set_clip_rectangle (&r, area);
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+ cl_rectangle_reset_clip_rectangle (&r);
+
+ gdk_gc_set_foreground (clearlooks_style->spot2_gc, &prev_foreground);
+ }
+
+ else if ( widget && (DETAIL ("menubar") || DETAIL ("toolbar") || DETAIL ("dockitem_bin") || DETAIL ("handlebox_bin")) && shadow_type != GTK_SHADOW_NONE) /* Toolbars and menus */
+ {
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], area);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], area);
+ }
+
+ gtk_style_apply_default_background (style, window,
+ widget && !GTK_WIDGET_NO_WINDOW (widget),
+ state_type, area, x, y, width, height);
+
+ /* we only want the borders on horizontal toolbars */
+ if ( DETAIL ("menubar") || height < 2*width ) {
+ if (!DETAIL ("menubar"))
+ gdk_draw_line (window, clearlooks_style->shade_gc[0],
+ x, y, x + width, y); /* top */
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[3],
+ x, y + height - 1, x + width, y + height - 1); /* bottom */
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[0], NULL);
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[3], NULL);
+ }
+ }
+ else
+ {
+ parent_class->draw_box (style, window, state_type, shadow_type, area,
+ widget, detail, x, y, width, height);
+ }
+}
+
+/**************************************************************************/
+
+static void
+ensure_check_pixmaps (GtkStyle *style,
+ GtkStateType state,
+ GdkScreen *screen,
+ gboolean treeview)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ ClearlooksRcStyle *clearlooks_rc = CLEARLOOKS_RC_STYLE (style->rc_style);
+ GdkPixbuf *check, *base, *inconsistent, *composite;
+ GdkColor *spot_color = clearlooks_get_spot_color (clearlooks_rc);
+
+ if (clearlooks_style->check_pixmap_nonactive[state] != NULL)
+ return;
+
+ if (state == GTK_STATE_ACTIVE || state == GTK_STATE_SELECTED) {
+ check = generate_bit (check_alpha, &style->text[GTK_STATE_NORMAL], 1.0);
+ inconsistent = generate_bit (check_inconsistent_alpha, &style->text[GTK_STATE_NORMAL], 1.0);
+ } else {
+ check = generate_bit (check_alpha, &style->text[state], 1.0);
+ inconsistent = generate_bit (check_inconsistent_alpha, &style->text[state], 1.0);
+ }
+
+ if (state == GTK_STATE_ACTIVE && !treeview)
+ base = generate_bit (check_base_alpha, &style->bg[state], 1.0);
+ else
+ base = generate_bit (check_base_alpha, &style->base[GTK_STATE_NORMAL], 1.0);
+
+ if (treeview)
+ composite = generate_bit (NULL, &clearlooks_style->shade[6], 1.0);
+ else
+ composite = generate_bit (NULL, &clearlooks_style->shade[5], 1.0);
+
+ gdk_pixbuf_composite (base, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->check_pixmap_nonactive[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ gdk_pixbuf_composite (check, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->check_pixmap_active[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ g_object_unref (composite);
+
+ composite = generate_bit (NULL, &clearlooks_style->shade[6], 1.0);
+
+ gdk_pixbuf_composite (base, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ gdk_pixbuf_composite (inconsistent, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->check_pixmap_inconsistent[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ g_object_unref (composite);
+ g_object_unref (base);
+ g_object_unref (check);
+ g_object_unref (inconsistent);
+}
+
+static void
+draw_check (DRAW_ARGS)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkGC *gc = style->base_gc[state_type];
+ GdkPixmap *pixmap;
+ gboolean treeview;
+
+ if (DETAIL ("check")) /* Menu item */
+ {
+ parent_class->draw_check (style, window, state_type, shadow_type, area,
+ widget, detail, x, y, width, height);
+ return;
+ }
+
+ treeview = widget && GTK_IS_TREE_VIEW(widget);
+ ensure_check_pixmaps (style, state_type, gtk_widget_get_screen (widget), treeview);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ if (shadow_type == GTK_SHADOW_IN)
+ pixmap = clearlooks_style->check_pixmap_active[state_type];
+ else if (shadow_type == GTK_SHADOW_ETCHED_IN) /* inconsistent */
+ pixmap = clearlooks_style->check_pixmap_inconsistent[state_type];
+ else
+ pixmap = clearlooks_style->check_pixmap_nonactive[state_type];
+
+ x += (width - CHECK_SIZE)/2;
+ y += (height - CHECK_SIZE)/2;
+
+ gdk_draw_drawable (window, gc, pixmap, 0, 0, x, y, CHECK_SIZE, CHECK_SIZE);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+}
+
+/**************************************************************************/
+static void
+draw_slider (DRAW_ARGS, GtkOrientation orientation)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkGC *shade_gc = clearlooks_style->shade_gc[4];
+ GdkGC *white_gc = clearlooks_style->shade_gc[0];
+ int x1, y1;
+
+#if DEBUG
+ printf("draw_slider: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ gtk_paint_box (style, window, state_type, shadow_type,
+ area, widget, detail, x, y, width, height);
+
+ if ((orientation == GTK_ORIENTATION_VERTICAL && height < 20) ||
+ (orientation == GTK_ORIENTATION_HORIZONTAL && width < 20))
+ return;
+
+ if (detail && strcmp ("slider", detail) == 0)
+ {
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (shade_gc, area);
+ gdk_gc_set_clip_rectangle (white_gc, area);
+ }
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ x1 = x + width / 2 - 4;
+ y1 = y + (height - 6) / 2;
+ gdk_draw_line (window, shade_gc, x1, y1, x1, y1 + 6);
+ gdk_draw_line (window, white_gc, x1 + 1, y1, x1 + 1, y1 + 6);
+ gdk_draw_line (window, shade_gc, x1 + 3, y1, x1 + 3, y1 + 6);
+ gdk_draw_line (window, white_gc, x1 + 3 + 1, y1, x1 + 3 + 1, y1 + 6);
+ gdk_draw_line (window, shade_gc, x1 + 3*2, y1, x1 + 3*2, y1 + 6);
+ gdk_draw_line (window, white_gc, x1 + 3*2 + 1, y1, x1 + 3*2 + 1, y1 + 6);
+ }
+ else
+ {
+ x1 = x + (width - 6) / 2;
+ y1 = y + height / 2 - 4;
+ gdk_draw_line (window, shade_gc, x1 + 6, y1, x1, y1);
+ gdk_draw_line (window, white_gc, x1 + 6, y1 + 1, x1, y1 + 1);
+ gdk_draw_line (window, shade_gc, x1 + 6, y1 + 3, x1, y1 + 3);
+ gdk_draw_line (window, white_gc, x1 + 6, y1 + 3 + 1, x1, y1 + 3 + 1);
+ gdk_draw_line (window, shade_gc, x1 + 6, y1 + 3*2, x1, y1 + 3*2);
+ gdk_draw_line (window, white_gc, x1 + 6, y1 + 3*2 + 1, x1, y1 + 3*2 + 1);
+ }
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (shade_gc, NULL);
+ gdk_gc_set_clip_rectangle (white_gc, NULL);
+ }
+ }
+ else if (detail && (strcmp ("hscale", detail) == 0 || strcmp ("vscale", detail) == 0))
+ {
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (shade_gc, area);
+ gdk_gc_set_clip_rectangle (white_gc, area);
+ }
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ x1 = x + width / 2 - 3;
+ y1 = y + (height - 7) / 2;
+ gdk_draw_line (window, shade_gc, x1 + 0, y1 + 5, x1 + 0, y1 + 1);
+ gdk_draw_line (window, white_gc, x1 + 1, y1 + 5, x1 + 1, y1 + 1);
+ gdk_draw_line (window, shade_gc, x1 + 3, y1 + 5, x1 + 3, y1 + 1);
+ gdk_draw_line (window, white_gc, x1 + 4, y1 + 5, x1 + 4, y1 + 1);
+ gdk_draw_line (window, shade_gc, x1 + 6, y1 + 5, x1 + 6, y1 + 1);
+ gdk_draw_line (window, white_gc, x1 + 7, y1 + 5, x1 + 7, y1 + 1);
+ }
+ else
+ {
+ x1 = x + (width - 7) / 2;
+ y1 = y + height / 2 - 3;
+ gdk_draw_line (window, shade_gc, x1 + 5, y1 + 0, x1 + 1, y1 + 0);
+ gdk_draw_line (window, white_gc, x1 + 5, y1 + 1, x1 + 1, y1 + 1);
+ gdk_draw_line (window, shade_gc, x1 + 5, y1 + 3, x1 + 1, y1 + 3);
+ gdk_draw_line (window, white_gc, x1 + 5, y1 + 4, x1 + 1, y1 + 4);
+ gdk_draw_line (window, shade_gc, x1 + 5, y1 + 6, x1 + 1, y1 + 6);
+ gdk_draw_line (window, white_gc, x1 + 5, y1 + 7, x1 + 1, y1 + 7);
+ }
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (shade_gc, NULL);
+ gdk_gc_set_clip_rectangle (white_gc, NULL);
+ }
+ }
+}
+
+/**************************************************************************/
+static void
+ensure_radio_pixmaps (GtkStyle *style,
+ GtkStateType state,
+ GdkScreen *screen)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ ClearlooksRcStyle *clearlooks_rc = CLEARLOOKS_RC_STYLE (style->rc_style);
+ GdkPixbuf *dot, *circle, *outline, *inconsistent, *composite;
+ GdkColor *spot_color = clearlooks_get_spot_color (clearlooks_rc);
+ GdkColor *composite_color;
+
+ if (clearlooks_style->radio_pixmap_nonactive[state] != NULL)
+ return;
+
+ if (state == GTK_STATE_ACTIVE || state == GTK_STATE_SELECTED) {
+ dot = colorize_bit (dot_intensity, dot_alpha, &style->text[GTK_STATE_NORMAL]);
+ inconsistent = generate_bit (inconsistent_alpha, &style->text[GTK_STATE_NORMAL], 1.0);
+ } else {
+ dot = colorize_bit (dot_intensity, dot_alpha, &style->text[state]);
+ inconsistent = generate_bit (inconsistent_alpha, &style->text[state], 1.0);
+ }
+
+ outline = generate_bit (outline_alpha, &clearlooks_style->shade[5], 1.0);
+
+ if (clearlooks_style->radio_pixmap_mask == NULL)
+ {
+ gdk_pixbuf_render_pixmap_and_mask (outline,
+ NULL,
+ &clearlooks_style->radio_pixmap_mask,
+ 1);
+ }
+
+ if (state == GTK_STATE_ACTIVE)
+ {
+ composite_color = &style->bg[GTK_STATE_PRELIGHT];
+ circle = generate_bit (circle_alpha, &style->bg[state], 1.0);
+ }
+ else
+ {
+ composite_color = &style->bg[state];
+ circle = generate_bit (circle_alpha, &style->base[GTK_STATE_NORMAL], 1.0);
+ }
+
+ composite = generate_bit (NULL, composite_color, 1.0);
+
+ gdk_pixbuf_composite (outline, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ gdk_pixbuf_composite (circle, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->radio_pixmap_nonactive[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ gdk_pixbuf_composite (dot, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->radio_pixmap_active[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ g_object_unref (composite);
+
+ composite = generate_bit (NULL, composite_color,1.0);
+
+ gdk_pixbuf_composite (outline, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+ gdk_pixbuf_composite (circle, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+ gdk_pixbuf_composite (inconsistent, composite,
+ 0, 0, RADIO_SIZE, RADIO_SIZE, 0, 0,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ clearlooks_style->radio_pixmap_inconsistent[state] =
+ pixbuf_to_pixmap (style, composite, screen);
+
+ g_object_unref (composite);
+ g_object_unref (circle);
+ g_object_unref (dot);
+ g_object_unref (inconsistent);
+ g_object_unref (outline);
+}
+
+static void
+draw_option (DRAW_ARGS)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkGC *gc = style->base_gc[state_type];
+ GdkPixmap *pixmap;
+
+ if (DETAIL ("option")) /* Menu item */
+ {
+ parent_class->draw_option (style, window, state_type, shadow_type,
+ area, widget, detail, x, y, width, height);
+ return;
+ }
+
+ ensure_radio_pixmaps (style, state_type, gtk_widget_get_screen (widget));
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ if (shadow_type == GTK_SHADOW_IN)
+ pixmap = clearlooks_style->radio_pixmap_active[state_type];
+ else if (shadow_type == GTK_SHADOW_ETCHED_IN) /* inconsistent */
+ pixmap = clearlooks_style->radio_pixmap_inconsistent[state_type];
+ else
+ pixmap = clearlooks_style->radio_pixmap_nonactive[state_type];
+
+ x += (width - RADIO_SIZE)/2;
+ y += (height - RADIO_SIZE)/2;
+
+ gdk_gc_set_clip_mask (gc, clearlooks_style->radio_pixmap_mask);
+ gdk_gc_set_clip_origin (gc, x, y);
+
+ gdk_draw_drawable (window, gc, pixmap, 0, 0, x, y,
+ RADIO_SIZE, RADIO_SIZE);
+
+ gdk_gc_set_clip_origin (gc, 0, 0);
+ gdk_gc_set_clip_mask (gc, NULL);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+}
+
+/**************************************************************************/
+
+static void
+draw_shadow_gap (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gint gap_x,
+ gint gap_width)
+{
+ /* I need to improve this function. */
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ CLRectangle r;
+ GdkRegion *area_region = NULL,
+ *gap_region = NULL;
+
+#if DEBUG
+ printf("draw_shadow_gap: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ sanitize_size (window, &width, &height);
+
+ cl_rectangle_reset (&r, style);
+ cl_rectangle_set_corners (&r, CL_CORNER_NONE, CL_CORNER_NONE,
+ CL_CORNER_NONE, CL_CORNER_NONE);
+
+ if (area)
+ {
+ area_region = gdk_region_rectangle (area);
+
+ switch (gap_side)
+ {
+ case GTK_POS_TOP:
+ {
+ GdkRectangle rect = { x+gap_x, y, gap_width, 2 };
+ gap_region = gdk_region_rectangle (&rect);
+ break;
+ }
+ case GTK_POS_BOTTOM:
+ {
+ GdkRectangle rect = { x+gap_x, y+height-2, gap_width, 2 };
+ gap_region = gdk_region_rectangle (&rect);
+ break;
+ }
+ case GTK_POS_LEFT:
+ {
+ GdkRectangle rect = { x, y+gap_x, 2, gap_width };
+ gap_region = gdk_region_rectangle (&rect);
+ break;
+ }
+ case GTK_POS_RIGHT:
+ {
+ GdkRectangle rect = { x+width-2, y+gap_x, 2, gap_width };
+ gap_region = gdk_region_rectangle (&rect);
+ break;
+ }
+ }
+
+ gdk_region_subtract (area_region, gap_region);
+ }
+
+ if (shadow_type == GTK_SHADOW_ETCHED_IN ||
+ shadow_type == GTK_SHADOW_ETCHED_OUT)
+ {
+ GdkGC *a;
+ GdkGC *b;
+
+ if (shadow_type == GTK_SHADOW_ETCHED_IN)
+ {
+ a = style->light_gc[state_type];
+ b = clearlooks_style->shade_gc[3];
+ }
+ else
+ {
+ a = clearlooks_style->shade_gc[3];
+ b = style->light_gc[state_type];
+ }
+
+ gdk_gc_set_clip_region (a, area_region);
+ gdk_gc_set_clip_region (b, area_region);
+
+ r.bordergc = a;
+ cl_draw_rectangle (window, widget, style, x+1, y+1, width-1, height-1, &r);
+
+ r.bordergc = b;
+ cl_draw_rectangle (window, widget, style, x, y, width-1, height-1, &r);
+
+ gdk_gc_set_clip_region (a, NULL);
+ gdk_gc_set_clip_region (b, NULL);
+ }
+ else if (shadow_type == GTK_SHADOW_IN || shadow_type == GTK_SHADOW_OUT)
+ {
+ r.topleft = (shadow_type == GTK_SHADOW_OUT) ? style->light_gc[state_type] : clearlooks_style->shade_gc[1];
+ r.bottomright = (shadow_type == GTK_SHADOW_OUT) ? clearlooks_style->shade_gc[1] : style->light_gc[state_type];
+ r.bordergc = clearlooks_style->shade_gc[5];
+
+ gdk_gc_set_clip_region (r.bordergc, area_region);
+ gdk_gc_set_clip_region (r.topleft, area_region);
+ gdk_gc_set_clip_region (r.bottomright, area_region);
+
+ cl_draw_rectangle (window, widget, style, x, y, width, height, &r);
+
+ cl_draw_shadow (window, widget, style, x, y, width, height, &r);
+
+ gdk_gc_set_clip_region (r.bordergc, NULL);
+ gdk_gc_set_clip_region (r.topleft, NULL);
+ gdk_gc_set_clip_region (r.bottomright, NULL);
+ }
+
+ if (area_region)
+ gdk_region_destroy (area_region);
+}
+
+/**************************************************************************/
+static void
+draw_hline (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ gint x1,
+ gint x2,
+ gint y)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+
+#if DEBUG
+ printf("draw_hline\n");
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[2], area);
+
+ if (detail && !strcmp (detail, "label"))
+ {
+ if (state_type == GTK_STATE_INSENSITIVE)
+ gdk_draw_line (window, style->light_gc[state_type], x1 + 1, y + 1, x2 + 1, y + 1);
+
+ gdk_draw_line (window, style->fg_gc[state_type], x1, y, x2, y);
+ }
+ else
+ {
+ gdk_draw_line (window, clearlooks_style->shade_gc[2], x1, y, x2, y);
+
+ /* if (DETAIL ("menuitem")) */
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x1, y+1, x2, y+1);
+ }
+
+ if (area)
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[2], NULL);
+}
+
+/**************************************************************************/
+static void
+draw_vline (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ gint y1,
+ gint y2,
+ gint x)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ gint thickness_light;
+ gint thickness_dark;
+
+#if DEBUG
+ printf("draw_vline\n");
+#endif
+
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ thickness_light = style->xthickness / 2;
+ thickness_dark = style->xthickness - thickness_light;
+
+ if (area)
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[2], area);
+
+ gdk_draw_line (window, clearlooks_style->shade_gc[2], x, y1, x, y2 - 1);
+ gdk_draw_line (window, clearlooks_style->shade_gc[0], x+1, y1, x+1, y2 - 1);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (clearlooks_style->shade_gc[2], NULL);
+}
+
+/**************************************************************************/
+static void
+draw_focus (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkPoint points[5];
+ GdkGC *gc;
+ gboolean free_dash_list = FALSE;
+ gint line_width = 1;
+ gchar *dash_list = "\1\1";
+ gint dash_len;
+
+#if DEBUG
+ printf("draw_focus: %s %d %d %d %d\n", detail, x, y, width, height);
+#endif
+
+ gc = clearlooks_style->shade_gc[6];
+
+ if (widget)
+ {
+ gtk_widget_style_get (widget,
+ "focus-line-width", &line_width,
+ "focus-line-pattern", (gchar *)&dash_list,
+ NULL);
+
+ free_dash_list = TRUE;
+ }
+
+ sanitize_size (window, &width, &height);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ gdk_gc_set_line_attributes (gc, line_width,
+ dash_list[0] ? GDK_LINE_ON_OFF_DASH : GDK_LINE_SOLID,
+ GDK_CAP_BUTT, GDK_JOIN_MITER);
+
+
+ if (detail && !strcmp (detail, "add-mode"))
+ {
+ if (free_dash_list)
+ g_free (dash_list);
+
+ dash_list = "\4\4";
+ free_dash_list = FALSE;
+ }
+
+ points[0].x = x + line_width / 2;
+ points[0].y = y + line_width / 2;
+ points[1].x = x + width - line_width + line_width / 2;
+ points[1].y = y + line_width / 2;
+ points[2].x = x + width - line_width + line_width / 2;
+ points[2].y = y + height - line_width + line_width / 2;
+ points[3].x = x + line_width / 2;
+ points[3].y = y + height - line_width + line_width / 2;
+ points[4] = points[0];
+
+ if (!dash_list[0])
+ {
+ gdk_draw_lines (window, gc, points, 5);
+ }
+ else
+ {
+ dash_len = strlen (dash_list);
+
+ if (dash_list[0])
+ gdk_gc_set_dashes (gc, 0, dash_list, dash_len);
+
+ gdk_draw_lines (window, gc, points, 3);
+
+ points[2].x += 1;
+
+ if (dash_list[0])
+ {
+ gint dash_pixels = 0;
+ gint i;
+
+ /* Adjust the dash offset for the bottom and left so we
+ * match up at the upper left.
+ */
+ for (i = 0; i < dash_len; i++)
+ dash_pixels += dash_list[i];
+
+ if (dash_len % 2 == 1)
+ dash_pixels *= 2;
+
+ gdk_gc_set_dashes (gc,
+ dash_pixels - (width + height - 2 * line_width) % dash_pixels,
+ dash_list, dash_len);
+ }
+
+ gdk_draw_lines (window, gc, points + 2, 3);
+ }
+
+ gdk_gc_set_line_attributes (gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+
+ if (free_dash_list)
+ g_free (dash_list);
+}
+
+static void
+draw_layout(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state_type,
+ gboolean use_text,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ const gchar * detail, gint x, gint y, PangoLayout * layout)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+
+ g_return_if_fail(GTK_IS_STYLE (style));
+ g_return_if_fail(window != NULL);
+
+ parent_class->draw_layout(style, window, state_type, use_text,
+ area, widget, detail, x, y, layout);
+
+
+}
+
+/**************************************************************************/
+static void
+draw_resize_grip (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ const gchar *detail,
+ GdkWindowEdge edge,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (window != NULL);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (style->light_gc[state_type], area);
+ gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area);
+ }
+
+ switch (edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ /* make it square */
+ if (width < height)
+ {
+ height = width;
+ }
+ else if (height < width)
+ {
+ width = height;
+ }
+ break;
+ case GDK_WINDOW_EDGE_NORTH:
+ if (width < height)
+ {
+ height = width;
+ }
+ break;
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ /* make it square, aligning to top right */
+ if (width < height)
+ {
+ height = width;
+ }
+ else if (height < width)
+ {
+ x += (width - height);
+ width = height;
+ }
+ break;
+ case GDK_WINDOW_EDGE_WEST:
+ if (height < width)
+ {
+ width = height;
+ }
+ break;
+ case GDK_WINDOW_EDGE_EAST:
+ /* aligning to right */
+ if (height < width)
+ {
+ x += (width - height);
+ width = height;
+ }
+ break;
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ /* make it square, aligning to bottom left */
+ if (width < height)
+ {
+ y += (height - width);
+ height = width;
+ }
+ else if (height < width)
+ {
+ width = height;
+ }
+ break;
+ case GDK_WINDOW_EDGE_SOUTH:
+ /* align to bottom */
+ if (width < height)
+ {
+ y += (height - width);
+ height = width;
+ }
+ break;
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ /* make it square, aligning to bottom right */
+ if (width < height)
+ {
+ y += (height - width);
+ height = width;
+ }
+ else if (height < width)
+ {
+ x += (width - height);
+ width = height;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* Clear background */
+ gtk_style_apply_default_background (style, window, FALSE,
+ state_type, area,
+ x, y, width, height);
+
+ switch (edge)
+ {
+ case GDK_WINDOW_EDGE_WEST:
+ case GDK_WINDOW_EDGE_EAST:
+ {
+ gint xi;
+
+ xi = x;
+
+ while (xi < x + width)
+ {
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ xi, y,
+ xi, y + height);
+
+ xi++;
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ xi, y,
+ xi, y + height);
+
+ xi += 2;
+ }
+ }
+ break;
+ case GDK_WINDOW_EDGE_NORTH:
+ case GDK_WINDOW_EDGE_SOUTH:
+ {
+ gint yi;
+
+ yi = y;
+
+ while (yi < y + height)
+ {
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ x, yi,
+ x + width, yi);
+
+ yi++;
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ x, yi,
+ x + width, yi);
+
+ yi+= 2;
+ }
+ }
+ break;
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ {
+ gint xi, yi;
+
+ xi = x + width;
+ yi = y + height;
+
+ while (xi > x + 3)
+ {
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ xi, y,
+ x, yi);
+
+ --xi;
+ --yi;
+
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ xi, y,
+ x, yi);
+
+ xi -= 3;
+ yi -= 3;
+
+ }
+ }
+ break;
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ {
+ gint xi, yi;
+
+ xi = x;
+ yi = y + height;
+
+ while (xi < (x + width - 3))
+ {
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ xi, y,
+ x + width, yi);
+
+ ++xi;
+ --yi;
+
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ xi, y,
+ x + width, yi);
+
+ xi += 3;
+ yi -= 3;
+ }
+ }
+ break;
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ {
+ gint xi, yi;
+
+ xi = x + width;
+ yi = y;
+
+ while (xi > x + 3)
+ {
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ x, yi,
+ xi, y + height);
+
+ --xi;
+ ++yi;
+
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ x, yi,
+ xi, y + height);
+
+ xi -= 3;
+ yi += 3;
+
+ }
+ }
+ break;
+
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ {
+ gint xi, yi;
+
+ xi = x;
+ yi = y;
+
+ while (xi < (x + width - 3))
+ {
+ gdk_draw_line (window,
+ style->light_gc[state_type],
+ xi, y + height,
+ x + width, yi);
+
+ ++xi;
+ ++yi;
+
+ gdk_draw_line (window,
+ clearlooks_style->shade_gc[4],
+ xi, y + height,
+ x + width, yi);
+
+ xi += 3;
+ yi += 3;
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL);
+ gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
+ gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL);
+ }
+}
+
+/**************************************************************************/
+
+static void
+clearlooks_style_init_from_rc (GtkStyle * style,
+ GtkRcStyle * rc_style)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ GdkColor *spot_color;
+ double shades[] = {1.065, 0.93, 0.896, 0.85, 0.768, 0.665, 0.4, 0.205};
+ int i;
+ double contrast;
+
+ parent_class->init_from_rc (style, rc_style);
+
+ contrast = CLEARLOOKS_RC_STYLE (rc_style)->contrast;
+
+ clearlooks_style->sunkenmenubar = CLEARLOOKS_RC_STYLE (rc_style)->sunkenmenubar;
+ clearlooks_style->progressbarstyle = CLEARLOOKS_RC_STYLE (rc_style)->progressbarstyle;
+ clearlooks_style->menubarstyle = CLEARLOOKS_RC_STYLE (rc_style)->menubarstyle;
+ clearlooks_style->menuitemstyle = CLEARLOOKS_RC_STYLE (rc_style)->menuitemstyle;
+ clearlooks_style->listviewitemstyle = CLEARLOOKS_RC_STYLE (rc_style)->listviewitemstyle;
+
+ /* Lighter to darker */
+ for (i = 0; i < 8; i++)
+ {
+ shade (&style->bg[GTK_STATE_NORMAL], &clearlooks_style->shade[i],
+ (shades[i]-0.7) * contrast + 0.7);
+ }
+
+ spot_color = clearlooks_get_spot_color (CLEARLOOKS_RC_STYLE (rc_style));
+
+ clearlooks_style->spot_color = *spot_color;
+ shade (&clearlooks_style->spot_color, &clearlooks_style->spot1, 1.42);
+ shade (&clearlooks_style->spot_color, &clearlooks_style->spot2, 1.05);
+ shade (&clearlooks_style->spot_color, &clearlooks_style->spot3, 0.65);
+
+ shade (&style->bg[GTK_STATE_NORMAL], &clearlooks_style->border[CL_BORDER_UPPER], 0.5);
+ shade (&style->bg[GTK_STATE_NORMAL], &clearlooks_style->border[CL_BORDER_LOWER], 0.62);
+ shade (&style->bg[GTK_STATE_ACTIVE], &clearlooks_style->border[CL_BORDER_UPPER_ACTIVE], 0.5);
+ shade (&style->bg[GTK_STATE_ACTIVE], &clearlooks_style->border[CL_BORDER_LOWER_ACTIVE], 0.55);
+}
+
+static GdkGC *
+realize_color (GtkStyle * style,
+ GdkColor * color)
+{
+ GdkGCValues gc_values;
+
+ gdk_colormap_alloc_color (style->colormap, color, FALSE, TRUE);
+
+ gc_values.foreground = *color;
+
+ return gtk_gc_get (style->depth, style->colormap, &gc_values, GDK_GC_FOREGROUND);
+}
+
+static void
+clearlooks_style_realize (GtkStyle * style)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int i;
+
+ parent_class->realize (style);
+
+ for (i = 0; i < 8; i++)
+ clearlooks_style->shade_gc[i] = realize_color (style, &clearlooks_style->shade[i]);
+
+ for (i=0; i < CL_BORDER_COUNT; i++)
+ clearlooks_style->border_gc[i] = realize_color (style, &clearlooks_style->border[i]);
+
+ clearlooks_style->spot1_gc = realize_color (style, &clearlooks_style->spot1);
+ clearlooks_style->spot2_gc = realize_color (style, &clearlooks_style->spot2);
+ clearlooks_style->spot3_gc = realize_color (style, &clearlooks_style->spot3);
+
+ /* set light inset color */
+ for (i=0; i<5; i++)
+ {
+ shade (&style->bg[i], &clearlooks_style->inset_dark[i], 0.93);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->inset_dark[i]);
+
+ shade (&style->bg[i], &clearlooks_style->inset_light[i], 1.055);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->inset_light[i]);
+
+ shade (&style->bg[i], &clearlooks_style->listview_bg[i], 1.015);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->listview_bg[i]);
+
+ /* CREATE GRADIENT FOR BUTTONS */
+ shade (&style->bg[i], &clearlooks_style->button_g1[i], 1.055);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->button_g1[i]);
+
+ shade (&style->bg[i], &clearlooks_style->button_g2[i], 1.005);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->button_g2[i]);
+
+ shade (&style->bg[i], &clearlooks_style->button_g3[i], 0.98);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->button_g3[i]);
+
+ shade (&style->bg[i], &clearlooks_style->button_g4[i], 0.91);
+ gdk_rgb_find_color (style->colormap, &clearlooks_style->button_g4[i]);
+ }
+
+}
+
+static void
+clearlooks_style_unrealize (GtkStyle * style)
+{
+ ClearlooksStyle *clearlooks_style = CLEARLOOKS_STYLE (style);
+ int i;
+
+ /* We don't free the colors, because we don't know if
+ * gtk_gc_release() actually freed the GC. FIXME - need
+ * a way of ref'ing colors explicitely so GtkGC can
+ * handle things properly.
+ */
+ for (i=0; i < 8; i++)
+ gtk_gc_release (clearlooks_style->shade_gc[i]);
+
+ gtk_gc_release (clearlooks_style->spot1_gc);
+ gtk_gc_release (clearlooks_style->spot2_gc);
+ gtk_gc_release (clearlooks_style->spot3_gc);
+
+ for (i = 0; i < 5; i++)
+ {
+ if (clearlooks_style->radio_pixmap_nonactive[i] != NULL)
+ {
+ g_object_unref (clearlooks_style->radio_pixmap_nonactive[i]);
+ clearlooks_style->radio_pixmap_nonactive[i] = NULL;
+ g_object_unref (clearlooks_style->radio_pixmap_active[i]);
+ clearlooks_style->radio_pixmap_active[i] = NULL;
+ g_object_unref (clearlooks_style->radio_pixmap_inconsistent[i]);
+ clearlooks_style->radio_pixmap_inconsistent[i] = NULL;
+ }
+
+ if (clearlooks_style->check_pixmap_nonactive[i] != NULL)
+ {
+ g_object_unref (clearlooks_style->check_pixmap_nonactive[i]);
+ clearlooks_style->check_pixmap_nonactive[i] = NULL;
+ g_object_unref (clearlooks_style->check_pixmap_active[i]);
+ clearlooks_style->check_pixmap_active[i] = NULL;
+ g_object_unref (clearlooks_style->check_pixmap_inconsistent[i]);
+ clearlooks_style->check_pixmap_inconsistent[i] = NULL;
+ }
+ }
+
+ if (clearlooks_style->radio_pixmap_mask != NULL)
+ g_object_unref (clearlooks_style->radio_pixmap_mask);
+
+ clearlooks_style->radio_pixmap_mask = NULL;
+
+ while (progressbars = g_list_first (progressbars))
+ cl_progressbar_remove (progressbars->data);
+
+ if (timer_id != 0)
+ {
+ g_source_remove(timer_id);
+ timer_id = 0;
+ }
+
+ parent_class->unrealize (style);
+}
+
+static GdkPixbuf *
+set_transparency (const GdkPixbuf *pixbuf, gdouble alpha_percent)
+{
+ GdkPixbuf *target;
+ guchar *data, *current;
+ guint x, y, rowstride, height, width;
+
+ g_return_val_if_fail (pixbuf != NULL, NULL);
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+ /* Returns a copy of pixbuf with it's non-completely-transparent pixels to
+ have an alpha level "alpha_percent" of their original value. */
+
+ target = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
+
+ if (alpha_percent == 1.0)
+ return target;
+ width = gdk_pixbuf_get_width (target);
+ height = gdk_pixbuf_get_height (target);
+ rowstride = gdk_pixbuf_get_rowstride (target);
+ data = gdk_pixbuf_get_pixels (target);
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ /* The "4" is the number of chars per pixel, in this case, RGBA,
+ the 3 means "skip to the alpha" */
+ current = data + (y * rowstride) + (x * 4) + 3;
+ *(current) = (guchar) (*(current) * alpha_percent);
+ }
+ }
+
+ return target;
+}
+
+static GdkPixbuf*
+scale_or_ref (GdkPixbuf *src,
+ int width,
+ int height)
+{
+ if (width == gdk_pixbuf_get_width (src) &&
+ height == gdk_pixbuf_get_height (src)) {
+ return g_object_ref (src);
+ } else {
+ return gdk_pixbuf_scale_simple (src,
+ width, height,
+ GDK_INTERP_BILINEAR);
+ }
+}
+
+static GdkPixbuf *
+render_icon (GtkStyle *style,
+ const GtkIconSource *source,
+ GtkTextDirection direction,
+ GtkStateType state,
+ GtkIconSize size,
+ GtkWidget *widget,
+ const char *detail)
+{
+ int width = 1;
+ int height = 1;
+ GdkPixbuf *scaled;
+ GdkPixbuf *stated;
+ GdkPixbuf *base_pixbuf;
+ GdkScreen *screen;
+ GtkSettings *settings;
+
+ /* Oddly, style can be NULL in this function, because
+ * GtkIconSet can be used without a style and if so
+ * it uses this function.
+ */
+
+ base_pixbuf = gtk_icon_source_get_pixbuf (source);
+
+ g_return_val_if_fail (base_pixbuf != NULL, NULL);
+
+ if (widget && gtk_widget_has_screen (widget)) {
+ screen = gtk_widget_get_screen (widget);
+ settings = gtk_settings_get_for_screen (screen);
+ } else if (style->colormap) {
+ screen = gdk_colormap_get_screen (style->colormap);
+ settings = gtk_settings_get_for_screen (screen);
+ } else {
+ settings = gtk_settings_get_default ();
+ GTK_NOTE (MULTIHEAD,
+ g_warning ("Using the default screen for gtk_default_render_icon()"));
+ }
+
+
+ if (size != (GtkIconSize) -1 && !gtk_icon_size_lookup_for_settings (settings, size, &width, &height)) {
+ g_warning (G_STRLOC ": invalid icon size '%d'", size);
+ return NULL;
+ }
+
+ /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise,
+ * leave it alone.
+ */
+ if (size != (GtkIconSize)-1 && gtk_icon_source_get_size_wildcarded (source))
+ scaled = scale_or_ref (base_pixbuf, width, height);
+ else
+ scaled = g_object_ref (base_pixbuf);
+
+ /* If the state was wildcarded, then generate a state. */
+ if (gtk_icon_source_get_state_wildcarded (source)) {
+ if (state == GTK_STATE_INSENSITIVE) {
+ stated = set_transparency (scaled, 0.3);
+#if 0
+ stated =
+ gdk_pixbuf_composite_color_simple (scaled,
+ gdk_pixbuf_get_width (scaled),
+ gdk_pixbuf_get_height (scaled),
+ GDK_INTERP_BILINEAR, 128,
+ gdk_pixbuf_get_width (scaled),
+ style->bg[state].pixel,
+ style->bg[state].pixel);
+#endif
+ gdk_pixbuf_saturate_and_pixelate (stated, stated,
+ 0.1, FALSE);
+
+ g_object_unref (scaled);
+ } else if (state == GTK_STATE_PRELIGHT) {
+ stated = gdk_pixbuf_copy (scaled);
+
+ gdk_pixbuf_saturate_and_pixelate (scaled, stated,
+ 1.2, FALSE);
+
+ g_object_unref (scaled);
+ } else {
+ stated = scaled;
+ }
+ }
+ else
+ stated = scaled;
+
+ return stated;
+}
+
+static void
+clearlooks_style_init (ClearlooksStyle * style)
+{
+}
+
+static void
+clearlooks_style_class_init (ClearlooksStyleClass * klass)
+{
+ GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ style_class->realize = clearlooks_style_realize;
+ style_class->unrealize = clearlooks_style_unrealize;
+ style_class->init_from_rc = clearlooks_style_init_from_rc;
+ style_class->draw_focus = draw_focus;
+ style_class->draw_resize_grip = draw_resize_grip;
+ style_class->draw_handle = draw_handle;
+ style_class->draw_vline = draw_vline;
+ style_class->draw_hline = draw_hline;
+ style_class->draw_slider = draw_slider;
+ style_class->draw_shadow_gap = draw_shadow_gap;
+ style_class->draw_arrow = clearlooks_draw_arrow;
+ style_class->draw_check = draw_check;
+ style_class->draw_tab = draw_tab;
+ style_class->draw_box = draw_box;
+ style_class->draw_shadow = draw_shadow;
+ style_class->draw_box_gap = draw_box_gap;
+ style_class->draw_extension = draw_extension;
+ style_class->draw_option = draw_option;
+ style_class->draw_layout = draw_layout;
+ style_class->render_icon = render_icon;
+ style_class->draw_flat_box = draw_flat_box;
+}
+
+GType clearlooks_type_style = 0;
+
+void
+clearlooks_style_register_type (GTypeModule * module)
+{
+ static const GTypeInfo object_info =
+ {
+ sizeof (ClearlooksStyleClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) clearlooks_style_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ClearlooksStyle),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) clearlooks_style_init,
+ NULL
+ };
+
+ clearlooks_type_style = g_type_module_register_type (module,
+ GTK_TYPE_STYLE,
+ "ClearlooksStyle",
+ &object_info, 0);
+}
diff --git a/libs/clearlooks/clearlooks_style.h b/libs/clearlooks/clearlooks_style.h
new file mode 100644
index 0000000000..1e07877bf7
--- /dev/null
+++ b/libs/clearlooks/clearlooks_style.h
@@ -0,0 +1,108 @@
+/* Clearlooks Engine
+ * Copyright (C) 2005 Richard Stellingwerff.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>
+ * and by Alexander Larsson <alexl@redhat.com>
+ * Modified by Richard Stellingwerff <remenic@gmail.com>
+ */
+#include <gtk/gtkstyle.h>
+
+#include "clearlooks_draw.h"
+
+typedef struct _ClearlooksStyle ClearlooksStyle;
+typedef struct _ClearlooksStyleClass ClearlooksStyleClass;
+
+extern GType clearlooks_type_style;
+
+#define CLEARLOOKS_TYPE_STYLE clearlooks_type_style
+#define CLEARLOOKS_STYLE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), CLEARLOOKS_TYPE_STYLE, ClearlooksStyle))
+#define CLEARLOOKS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLEARLOOKS_TYPE_STYLE, ClearlooksStyleClass))
+#define CLEARLOOKS_IS_STYLE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), CLEARLOOKS_TYPE_STYLE))
+#define CLEARLOOKS_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLEARLOOKS_TYPE_STYLE))
+#define CLEARLOOKS_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLEARLOOKS_TYPE_STYLE, ClearlooksStyleClass))
+
+typedef enum
+{
+ CL_BORDER_UPPER = 0,
+ CL_BORDER_LOWER,
+ CL_BORDER_UPPER_ACTIVE,
+ CL_BORDER_LOWER_ACTIVE,
+ CL_BORDER_COUNT
+} ClBorderColorType;
+
+typedef enum
+{
+ CL_SCROLLBUTTON_BEGIN = 0,
+ CL_SCROLLBUTTON_END,
+ CL_SCROLLBUTTON_OTHER
+} ClScrollButtonType;
+
+struct _ClearlooksStyle
+{
+ GtkStyle parent_instance;
+
+ GdkColor shade[9];
+
+ GdkColor spot_color;
+ GdkColor spot1;
+ GdkColor spot2;
+ GdkColor spot3;
+
+ GdkColor border[CL_BORDER_COUNT];
+
+ /* from light to dark */
+ GdkGC *shade_gc[9];
+ GdkGC *border_gc[CL_BORDER_COUNT];
+
+ GdkGC *spot1_gc;
+ GdkGC *spot2_gc;
+ GdkGC *spot3_gc;
+
+ GdkColor inset_light[5];
+ GdkColor inset_dark[5];
+
+ GdkColor button_g1[5];
+ GdkColor button_g2[5];
+ GdkColor button_g3[5];
+ GdkColor button_g4[5];
+
+ GdkColor listview_bg[5];
+
+ GdkPixmap *radio_pixmap_nonactive[5];
+ GdkPixmap *radio_pixmap_active[5];
+ GdkPixmap *radio_pixmap_inconsistent[5];
+ GdkBitmap *radio_pixmap_mask; /* All masks are the same */
+
+ GdkPixmap *check_pixmap_nonactive[5];
+ GdkPixmap *check_pixmap_active[5];
+ GdkPixmap *check_pixmap_inconsistent[5];
+
+ gboolean sunkenmenubar:1;
+
+ guint8 progressbarstyle;
+ guint8 menubarstyle;
+ guint8 menuitemstyle;
+ guint8 listviewitemstyle;
+};
+
+struct _ClearlooksStyleClass
+{
+ GtkStyleClass parent_class;
+};
+
+void clearlooks_style_register_type (GTypeModule *module);
diff --git a/libs/clearlooks/clearlooks_theme_main.c b/libs/clearlooks/clearlooks_theme_main.c
new file mode 100644
index 0000000000..d30d4dd0b7
--- /dev/null
+++ b/libs/clearlooks/clearlooks_theme_main.c
@@ -0,0 +1,37 @@
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include "clearlooks_style.h"
+#include "clearlooks_rc_style.h"
+
+G_MODULE_EXPORT void
+theme_init (GTypeModule *module)
+{
+ clearlooks_rc_style_register_type (module);
+ clearlooks_style_register_type (module);
+ printf("theme_init() called from internal clearlooks engine!\n");
+}
+
+G_MODULE_EXPORT void
+theme_exit (void)
+{
+}
+
+G_MODULE_EXPORT GtkRcStyle *
+theme_create_rc_style (void)
+{
+ return GTK_RC_STYLE (g_object_new (CLEARLOOKS_TYPE_RC_STYLE, NULL));
+}
+
+/* The following function will be called by GTK+ when the module
+ * is loaded and checks to see if we are compatible with the
+ * version of GTK+ that loads us.
+ */
+G_MODULE_EXPORT const gchar* g_module_check_init (GModule *module);
+const gchar*
+g_module_check_init (GModule *module)
+{
+ return gtk_check_version (GTK_MAJOR_VERSION,
+ GTK_MINOR_VERSION,
+ GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
+}
diff --git a/libs/clearlooks/cpdll.sh b/libs/clearlooks/cpdll.sh
new file mode 100755
index 0000000000..fb101d52a0
--- /dev/null
+++ b/libs/clearlooks/cpdll.sh
@@ -0,0 +1,2 @@
+mkdir engines
+cp libclearlooks.so engines
diff --git a/libs/clearlooks/support.c b/libs/clearlooks/support.c
new file mode 100644
index 0000000000..358c7f43fb
--- /dev/null
+++ b/libs/clearlooks/support.c
@@ -0,0 +1,981 @@
+#include "support.h"
+
+/* #define ALWAYS_DITHER_GRADIENTS */
+
+GtkTextDirection
+get_direction (GtkWidget *widget)
+{
+ GtkTextDirection dir;
+
+ if (widget)
+ dir = gtk_widget_get_direction (widget);
+ else
+ dir = GTK_TEXT_DIR_LTR;
+
+ return dir;
+}
+
+GdkPixbuf *
+generate_bit (unsigned char alpha[], GdkColor *color, double mult)
+{
+ guint r, g, b;
+ GdkPixbuf *pixbuf;
+ unsigned char *pixels;
+ int w, h, rs;
+ int x, y;
+
+ r = (color->red >> 8) * mult;
+ r = MIN(r, 255);
+ g = (color->green >> 8) * mult;
+ g = MIN(g, 255);
+ b = (color->blue >> 8) * mult;
+ b = MIN(b, 255);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+ rs = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+
+ for (y=0; y < h; y++)
+ {
+ for (x=0; x < w; x++)
+ {
+ pixels[y*rs + x*4 + 0] = r;
+ pixels[y*rs + x*4 + 1] = g;
+ pixels[y*rs + x*4 + 2] = b;
+ if (alpha)
+ pixels[y*rs + x*4 + 3] = alpha[y*w + x];
+ else
+ pixels[y*rs + x*4 + 3] = 255;
+ }
+ }
+
+ return pixbuf;
+}
+
+#define CLAMP_UCHAR(v) ((guchar) (CLAMP (((int)v), (int)0, (int)255)))
+
+GdkPixbuf *
+colorize_bit (unsigned char *bit,
+ unsigned char *alpha,
+ GdkColor *new_color)
+{
+ GdkPixbuf *pixbuf;
+ double intensity;
+ int x, y;
+ const guchar *src, *asrc;
+ guchar *dest;
+ int dest_rowstride;
+ int width, height;
+ guchar *dest_pixels;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
+
+ if (pixbuf == NULL)
+ return NULL;
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ for (y = 0; y < RADIO_SIZE; y++)
+ {
+ src = bit + y * RADIO_SIZE;
+ asrc = alpha + y * RADIO_SIZE;
+ dest = dest_pixels + y * dest_rowstride;
+
+ for (x = 0; x < RADIO_SIZE; x++)
+ {
+ double dr, dg, db;
+
+ intensity = (src[x] + 0 )/ 255.0;
+
+ if (intensity <= 0.5)
+ {
+ /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
+ dr = (new_color->red * intensity * 2.0) / 65535.0;
+ dg = (new_color->green * intensity * 2.0) / 65535.0;
+ db = (new_color->blue * intensity * 2.0) / 65535.0;
+ }
+ else
+ {
+ /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
+ dr = (new_color->red + (65535 - new_color->red) * (intensity - 0.5) * 2.0) / 65535.0;
+ dg = (new_color->green + (65535 - new_color->green) * (intensity - 0.5) * 2.0) / 65535.0;
+ db = (new_color->blue + (65535 - new_color->blue) * (intensity - 0.5) * 2.0) / 65535.0;
+ }
+
+ dest[0] = CLAMP_UCHAR (255 * dr);
+ dest[1] = CLAMP_UCHAR (255 * dg);
+ dest[2] = CLAMP_UCHAR (255 * db);
+
+ dest[3] = asrc[x];
+ dest += 4;
+ }
+ }
+
+ return pixbuf;
+}
+
+GdkPixmap *
+pixbuf_to_pixmap (GtkStyle *style,
+ GdkPixbuf *pixbuf,
+ GdkScreen *screen)
+{
+ GdkGC *tmp_gc;
+ GdkPixmap *pixmap;
+
+ pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen),
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ style->depth);
+
+ gdk_drawable_set_colormap (pixmap, style->colormap);
+
+ tmp_gc = gdk_gc_new (pixmap);
+
+ gdk_pixbuf_render_to_drawable (pixbuf, pixmap, tmp_gc, 0, 0, 0, 0,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+
+ gdk_gc_unref (tmp_gc);
+
+ return pixmap;
+}
+
+
+void
+rgb_to_hls (gdouble *r,
+ gdouble *g,
+ gdouble *b)
+{
+ gdouble min;
+ gdouble max;
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+ gdouble h, l, s;
+ gdouble delta;
+
+ red = *r;
+ green = *g;
+ blue = *b;
+
+ if (red > green)
+ {
+ if (red > blue)
+ max = red;
+ else
+ max = blue;
+
+ if (green < blue)
+ min = green;
+ else
+ min = blue;
+ }
+ else
+ {
+ if (green > blue)
+ max = green;
+ else
+ max = blue;
+
+ if (red < blue)
+ min = red;
+ else
+ min = blue;
+ }
+
+ l = (max + min) / 2;
+ s = 0;
+ h = 0;
+
+ if (max != min)
+ {
+ if (l <= 0.5)
+ s = (max - min) / (max + min);
+ else
+ s = (max - min) / (2 - max - min);
+
+ delta = max -min;
+ if (red == max)
+ h = (green - blue) / delta;
+ else if (green == max)
+ h = 2 + (blue - red) / delta;
+ else if (blue == max)
+ h = 4 + (red - green) / delta;
+
+ h *= 60;
+ if (h < 0.0)
+ h += 360;
+ }
+
+ *r = h;
+ *g = l;
+ *b = s;
+}
+
+void
+hls_to_rgb (gdouble *h,
+ gdouble *l,
+ gdouble *s)
+{
+ gdouble hue;
+ gdouble lightness;
+ gdouble saturation;
+ gdouble m1, m2;
+ gdouble r, g, b;
+
+ lightness = *l;
+ saturation = *s;
+
+ if (lightness <= 0.5)
+ m2 = lightness * (1 + saturation);
+ else
+ m2 = lightness + saturation - lightness * saturation;
+
+ m1 = 2 * lightness - m2;
+
+ if (saturation == 0)
+ {
+ *h = lightness;
+ *l = lightness;
+ *s = lightness;
+ }
+ else
+ {
+ hue = *h + 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ r = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ r = m2;
+ else if (hue < 240)
+ r = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ r = m1;
+
+ hue = *h;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ g = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ g = m2;
+ else if (hue < 240)
+ g = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ g = m1;
+
+ hue = *h - 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ b = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ b = m2;
+ else if (hue < 240)
+ b = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ b = m1;
+
+ *h = r;
+ *l = g;
+ *s = b;
+ }
+}
+
+void
+shade (GdkColor * a, GdkColor * b, float k)
+{
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+
+ red = (gdouble) a->red / 65535.0;
+ green = (gdouble) a->green / 65535.0;
+ blue = (gdouble) a->blue / 65535.0;
+
+ rgb_to_hls (&red, &green, &blue);
+
+ green *= k;
+ if (green > 1.0)
+ green = 1.0;
+ else if (green < 0.0)
+ green = 0.0;
+
+ blue *= k;
+ if (blue > 1.0)
+ blue = 1.0;
+ else if (blue < 0.0)
+ blue = 0.0;
+
+ hls_to_rgb (&red, &green, &blue);
+
+ b->red = red * 65535.0;
+ b->green = green * 65535.0;
+ b->blue = blue * 65535.0;
+}
+
+
+/**************************************************************************/
+
+void
+arrow_draw_hline (GdkWindow *window,
+ GdkGC *gc,
+ int x1,
+ int x2,
+ int y,
+ gboolean last)
+{
+ if (x2 - x1 < 7 && !last) /* 7 to get garretts pixels, otherwise 6 */
+ {
+ gdk_draw_line (window, gc, x1, y, x2, y);
+ }
+ else if (last)
+ {
+ /* we don't draw "spikes" for very small arrows */
+ if (x2 - x1 <= 9)
+ {
+ /*gdk_draw_line (window, gc, x1+1, y, x1+1, y);
+ gdk_draw_line (window, gc, x2-1, y, x2-1, y);*/
+ }
+ else
+ {
+ gdk_draw_line (window, gc, x1+2, y, x1+2, y);
+ gdk_draw_line (window, gc, x2-2, y, x2-2, y);
+ }
+ }
+ else
+ {
+ gdk_draw_line (window, gc, x1, y, x1+2, y);
+ gdk_draw_line (window, gc, x2-2, y, x2, y);
+ }
+}
+
+void
+arrow_draw_vline (GdkWindow *window,
+ GdkGC *gc,
+ int y1,
+ int y2,
+ int x,
+ gboolean last)
+{
+ if (y2 - y1 < 7 && !last) /* 7 to get garretts pixels */
+ gdk_draw_line (window, gc, x, y1, x, y2);
+ else if (last)
+ {
+ /* we don't draw "spikes" for very small arrows */
+ if (y2 - y1 > 9) {
+ gdk_draw_line (window, gc, x, y1+2, x, y1+2);
+ gdk_draw_line (window, gc, x, y2-2, x, y2-2);
+ }
+ }
+ else
+ {
+ gdk_draw_line (window, gc, x, y1, x, y1+2);
+ gdk_draw_line (window, gc, x, y2-2, x, y2);
+ }
+}
+
+
+
+void
+draw_arrow (GdkWindow *window,
+ GdkGC *gc,
+ GdkRectangle *area,
+ GtkArrowType arrow_type,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ gint i, j;
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ if (arrow_type == GTK_ARROW_DOWN)
+ {
+ for (i = 0, j = -1; i < height; i++, j++)
+ arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == 0);
+
+ }
+ else if (arrow_type == GTK_ARROW_UP)
+ {
+ for (i = height - 1, j = -1; i >= 0; i--, j++)
+ arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == height - 1);
+ }
+ else if (arrow_type == GTK_ARROW_LEFT)
+ {
+ for (i = width - 1, j = -1; i >= 0; i--, j++)
+ arrow_draw_vline (window, gc, y + j, y + height - j - 1, x + i, i == width - 1);
+ }
+ else if (arrow_type == GTK_ARROW_RIGHT)
+ {
+ for (i = 0, j = -1; i < width; i++, j++)
+ arrow_draw_vline (window, gc, y + j, y + height - j - 1, x + i, i == 0);
+ }
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+}
+
+void
+calculate_arrow_geometry (GtkArrowType arrow_type,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ gint w = *width;
+ gint h = *height;
+
+ switch (arrow_type)
+ {
+ case GTK_ARROW_UP:
+ case GTK_ARROW_DOWN:
+ w += (w % 2) - 1;
+ h = (w / 2 + 1) + 1;
+
+ if (h > *height)
+ {
+ h = *height;
+ w = 2 * (h - 1) - 1;
+ }
+
+ if (arrow_type == GTK_ARROW_DOWN)
+ {
+ if (*height % 2 == 1 || h % 2 == 0)
+ *height += 1;
+ }
+ else
+ {
+ if (*height % 2 == 0 || h % 2 == 0)
+ *height -= 1;
+ }
+ break;
+
+ case GTK_ARROW_RIGHT:
+ case GTK_ARROW_LEFT:
+ h += (h % 2) - 1;
+ w = (h / 2 + 1) + 1;
+
+ if (w > *width)
+ {
+ w = *width;
+ h = 2 * (w - 1) - 1;
+ }
+
+ if (arrow_type == GTK_ARROW_RIGHT)
+ {
+ if (*width % 2 == 1 || w % 2 == 0)
+ *width += 1;
+ }
+ else
+ {
+ if (*width % 2 == 0 || w % 2 == 0)
+ *width -= 1;
+ }
+ break;
+
+ default:
+ /* should not be reached */
+ break;
+ }
+
+ *x += (*width - w) / 2;
+ *y += (*height - h) / 2;
+ *height = h;
+ *width = w;
+}
+
+
+void gtk_treeview_get_header_index (GtkTreeView *tv, GtkWidget *header,
+ gint *column_index, gint *columns,
+gboolean *resizable)
+{
+ GList *list;
+ *column_index = *columns = 0;
+ list = gtk_tree_view_get_columns (tv);
+
+ do
+ {
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(list->data);
+ if ( column->button == header )
+ {
+ *column_index = *columns;
+ *resizable = column->resizable;
+ }
+ if ( column->visible )
+ (*columns)++;
+ } while ((list = g_list_next(list)));
+}
+
+void gtk_clist_get_header_index (GtkCList *clist, GtkWidget *button,
+ gint *column_index, gint *columns)
+{
+ *columns = clist->columns;
+ int i;
+
+ for (i=0; i<*columns; i++)
+ {
+ if (clist->column[i].button == button)
+ {
+ *column_index = i;
+ break;
+ }
+ }
+}
+
+gboolean
+sanitize_size (GdkWindow *window,
+ gint *width,
+ gint *height)
+{
+ gboolean set_bg = FALSE;
+
+ if ((*width == -1) && (*height == -1))
+ {
+ set_bg = GDK_IS_WINDOW (window);
+ gdk_window_get_size (window, width, height);
+ }
+ else if (*width == -1)
+ gdk_window_get_size (window, width, NULL);
+ else if (*height == -1)
+ gdk_window_get_size (window, NULL, height);
+
+ return set_bg;
+}
+
+static GtkRequisition default_option_indicator_size = { 7, 13 };
+static GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
+
+void
+option_menu_get_props (GtkWidget *widget,
+ GtkRequisition *indicator_size,
+ GtkBorder *indicator_spacing)
+{
+ GtkRequisition *tmp_size = NULL;
+ GtkBorder *tmp_spacing = NULL;
+
+ if (widget)
+ gtk_widget_style_get (widget, "indicator_size", &tmp_size,
+ "indicator_spacing", &tmp_spacing, NULL);
+
+ if (tmp_size)
+ {
+ *indicator_size = *tmp_size;
+ g_free (tmp_size);
+ }
+ else
+ *indicator_size = default_option_indicator_size;
+
+ if (tmp_spacing)
+ {
+ *indicator_spacing = *tmp_spacing;
+ g_free (tmp_spacing);
+ }
+ else
+ *indicator_spacing = default_option_indicator_spacing;
+}
+
+GtkWidget *special_get_ancestor(GtkWidget * widget,
+ GType widget_type)
+{
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
+
+ while (widget && widget->parent
+ && !g_type_is_a(GTK_WIDGET_TYPE(widget->parent),
+ widget_type))
+ widget = widget->parent;
+
+ if (!
+ (widget && widget->parent
+ && g_type_is_a(GTK_WIDGET_TYPE(widget->parent), widget_type)))
+ return NULL;
+
+ return widget;
+}
+
+/* Dithered Gradient Buffers */
+static void
+internel_image_buffer_free_pixels (guchar *pixels, gpointer data)
+{
+ g_free (pixels);
+}
+
+static GdkPixbuf*
+internal_image_buffer_new (gint width, gint height)
+{
+ guchar *buf;
+ int rowstride;
+
+ g_return_val_if_fail (width > 0, NULL);
+ g_return_val_if_fail (height > 0, NULL);
+
+ rowstride = width * 3;
+
+ buf = g_try_malloc (height * rowstride);
+
+ if (!buf)
+ return NULL;
+
+ return gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB,
+ FALSE, 8,
+ width, height, rowstride,
+ internel_image_buffer_free_pixels, NULL);
+}
+
+static void
+internal_color_get_as_uchars(GdkColor *color,
+ guchar *red,
+ guchar *green,
+ guchar *blue)
+{
+ *red = (guchar) (color->red / 256.0);
+ *green = (guchar) (color->green / 256.0);
+ *blue = (guchar) (color->blue / 256.0);
+}
+
+static GdkPixbuf*
+internal_create_horizontal_gradient_image_buffer (gint width, gint height,
+ GdkColor *from,
+ GdkColor *to)
+{
+ int i;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf* buffer;
+ guchar *ptr;
+ guchar *pixels;
+ guchar r0, g0, b0;
+ guchar rf, gf, bf;
+ int rowstride;
+
+ buffer = internal_image_buffer_new (width, height);
+
+ if (buffer == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (buffer);
+ ptr = pixels;
+ rowstride = gdk_pixbuf_get_rowstride (buffer);
+
+ internal_color_get_as_uchars(from, &r0, &g0, &b0);
+ internal_color_get_as_uchars(to, &rf, &gf, &bf);
+
+ r = r0 << 16;
+ g = g0 << 16;
+ b = b0 << 16;
+
+ dr = ((rf-r0)<<16)/width;
+ dg = ((gf-g0)<<16)/width;
+ db = ((bf-b0)<<16)/width;
+
+ /* render the first line */
+ for (i=0; i<width; i++)
+ {
+ *(ptr++) = (guchar)(r>>16);
+ *(ptr++) = (guchar)(g>>16);
+ *(ptr++) = (guchar)(b>>16);
+
+ r += dr;
+ g += dg;
+ b += db;
+ }
+
+ /* copy the first line to the other lines */
+ for (i=1; i<height; i++)
+ {
+ memcpy (&(pixels[i*rowstride]), pixels, rowstride);
+ }
+
+ return buffer;
+}
+
+static GdkPixbuf*
+internal_create_vertical_gradient_image_buffer (gint width, gint height,
+ GdkColor *from,
+ GdkColor *to)
+{
+ gint i, j, max_block, last_block;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf *buffer;
+
+ guchar *ptr;
+ guchar point[4];
+
+ guchar r0, g0, b0;
+ guchar rf, gf, bf;
+
+ gint rowstride;
+ guchar *pixels;
+
+ buffer = internal_image_buffer_new (width, height);
+
+ if (buffer == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (buffer);
+ rowstride = gdk_pixbuf_get_rowstride (buffer);
+
+ internal_color_get_as_uchars(from, &r0, &g0, &b0);
+ internal_color_get_as_uchars(to, &rf, &gf, &bf);
+
+ r = r0<<16;
+ g = g0<<16;
+ b = b0<<16;
+
+ dr = ((rf-r0)<<16)/height;
+ dg = ((gf-g0)<<16)/height;
+ db = ((bf-b0)<<16)/height;
+
+ max_block = width/2;
+
+ for (i=0; i < height; i++)
+ {
+ ptr = pixels + i * rowstride;
+
+ ptr[0] = r>>16;
+ ptr[1] = g>>16;
+ ptr[2] = b>>16;
+
+ if (width > 1)
+ {
+ last_block = 0;
+
+ for (j=1; j <= max_block; j *= 2)
+ {
+ memcpy (&(ptr[j*3]), ptr, j*3);
+
+ if ((j*2) >= max_block)
+ {
+ last_block = j*2;
+ }
+ }
+
+ if ((last_block < width) && (last_block > 0))
+ {
+ memcpy (&(ptr[last_block*3]), ptr, (width - last_block)*3);
+ }
+ }
+
+ r += dr;
+ g += dg;
+ b += db;
+ }
+
+ return buffer;
+}
+
+void
+draw_vgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
+ int x, int y, int width, int height,
+ GdkColor *left_color, GdkColor *right_color)
+{
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ gboolean dither = ((style->depth > 0) && (style->depth <= 16));
+ #endif
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ if ( left_color == NULL || right_color == NULL )
+ {
+ gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
+ return;
+ }
+
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ if (dither)
+ #endif
+ {
+ GdkPixbuf *image_buffer = NULL;
+
+ image_buffer = internal_create_horizontal_gradient_image_buffer (width, height, left_color, right_color);
+
+ if (image_buffer)
+ {
+ gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
+
+ g_object_unref(image_buffer);
+ }
+ }
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ else
+ {
+ int i;
+ GdkColor col;
+ int dr, dg, db;
+ GdkGCValues old_values;
+
+ gdk_gc_get_values (gc, &old_values);
+
+ if (left_color == right_color )
+ {
+ col = *left_color;
+ gdk_rgb_find_color (style->colormap, &col);
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
+ gdk_gc_set_foreground (gc, &old_values.foreground);
+ return;
+ }
+
+ col = *left_color;
+ dr = (right_color->red - left_color->red) / width;
+ dg = (right_color->green - left_color->green) / width;
+ db = (right_color->blue - left_color->blue) / width;
+
+ for (i = 0; i < width; i++)
+ {
+ gdk_rgb_find_color (style->colormap, &col);
+
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_line (drawable, gc, x + i, y, x + i, y + height - 1);
+
+ col.red += dr;
+ col.green += dg;
+ col.blue += db;
+ }
+
+ gdk_gc_set_foreground (gc, &old_values.foreground);
+ }
+ #endif
+}
+
+void
+draw_hgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
+ int x, int y, int width, int height,
+ GdkColor *top_color, GdkColor *bottom_color)
+{
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ gboolean dither = ((style->depth > 0) && (style->depth <= 16));
+ #endif
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ if (dither)
+ #endif
+ {
+ GdkPixbuf *image_buffer = NULL;
+
+ image_buffer = internal_create_vertical_gradient_image_buffer (width, height, top_color, bottom_color);
+
+ if (image_buffer)
+ {
+ gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
+
+ g_object_unref(image_buffer);
+ }
+ }
+ #ifndef ALWAYS_DITHER_GRADIENTS
+ else
+ {
+ int i;
+ GdkColor col;
+ int dr, dg, db;
+ GdkGCValues old_values;
+
+ gdk_gc_get_values (gc, &old_values);
+
+ if (top_color == bottom_color )
+ {
+ col = *top_color;
+ gdk_rgb_find_color (style->colormap, &col);
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
+ gdk_gc_set_foreground (gc, &old_values.foreground);
+ return;
+ }
+
+ col = *top_color;
+ dr = (bottom_color->red - top_color->red) / height;
+ dg = (bottom_color->green - top_color->green) / height;
+ db = (bottom_color->blue - top_color->blue) / height;
+
+ for (i = 0; i < height; i++)
+ {
+ gdk_rgb_find_color (style->colormap, &col);
+
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_line (drawable, gc, x, y + i, x + width - 1, y + i);
+
+ col.red += dr;
+ col.green += dg;
+ col.blue += db;
+ }
+
+ gdk_gc_set_foreground (gc, &old_values.foreground);
+ }
+ #endif
+}
+
+void blend (GdkColormap *colormap,
+ GdkColor *a, GdkColor *b, GdkColor *c, int alpha)
+{
+ int inAlpha = 100-alpha;
+ c->red = (a->red * alpha + b->red * inAlpha) / 100;
+ c->green = (a->green * alpha + b->green * inAlpha) / 100;
+ c->blue = (a->blue * alpha + b->blue * inAlpha) / 100;
+
+ gdk_rgb_find_color (colormap, c);
+}
+
+GtkWidget *get_parent_window (GtkWidget *widget)
+{
+ GtkWidget *parent = widget->parent;
+
+ while (parent && GTK_WIDGET_NO_WINDOW (parent))
+ parent = parent->parent;
+
+ return parent;
+}
+
+GdkColor *get_parent_bgcolor (GtkWidget *widget)
+{
+ GtkWidget *parent = get_parent_window (widget);
+
+ if (parent && parent->style)
+ return &parent->style->bg[GTK_STATE_NORMAL];
+
+ return NULL;
+}
+
+GtkWidget *
+find_combo_box_widget (GtkWidget * widget)
+{
+ GtkWidget *result = NULL;
+
+ if (widget && !GTK_IS_COMBO_BOX_ENTRY (widget))
+ {
+ if (GTK_IS_COMBO_BOX (widget))
+ result = widget;
+ else
+ result = find_combo_box_widget(widget->parent);
+ }
+
+ return result;
+}
+
+gboolean
+is_combo_box (GtkWidget * widget)
+{
+ return (find_combo_box_widget(widget) != NULL);
+}
diff --git a/libs/clearlooks/support.h b/libs/clearlooks/support.h
new file mode 100644
index 0000000000..a1430b40d0
--- /dev/null
+++ b/libs/clearlooks/support.h
@@ -0,0 +1,110 @@
+#include <gtk/gtk.h>
+#include <math.h>
+#include <string.h>
+
+/* GTK 2.2 compatibility */
+#ifndef GTK_IS_COMBO_BOX_ENTRY
+ #define GTK_IS_COMBO_BOX_ENTRY(x) 0
+#endif
+#ifndef GTK_IS_COMBO_BOX
+ #define GTK_IS_COMBO_BOX(x) 0
+#endif
+
+#define RADIO_SIZE 13
+#define CHECK_SIZE 13
+
+GtkTextDirection
+get_direction (GtkWidget *widget);
+
+GdkPixbuf *
+generate_bit (unsigned char alpha[],
+ GdkColor *color,
+ double mult);
+
+GdkPixbuf *
+colorize_bit (unsigned char *bit,
+ unsigned char *alpha,
+ GdkColor *new_color);
+
+GdkPixmap *
+pixbuf_to_pixmap (GtkStyle *style,
+ GdkPixbuf *pixbuf,
+ GdkScreen *screen);
+
+gboolean
+sanitize_size (GdkWindow *window,
+ gint *width,
+ gint *height);
+
+void
+rgb_to_hls (gdouble *r,
+ gdouble *g,
+ gdouble *b);
+
+void
+hls_to_rgb (gdouble *h,
+ gdouble *l,
+ gdouble *s);
+
+void
+shade (GdkColor * a, GdkColor * b, float k);
+
+void
+draw_hgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
+ int x, int y, int width, int height,
+ GdkColor *top_color, GdkColor *bottom_color);
+
+void
+draw_vgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
+ int x, int y, int width, int height,
+ GdkColor *left_color, GdkColor *right_color);
+
+void
+arrow_draw_hline (GdkWindow *window,
+ GdkGC *gc,
+ int x1,
+ int x2,
+ int y,
+ gboolean last);
+
+void
+arrow_draw_vline (GdkWindow *window,
+ GdkGC *gc,
+ int y1,
+ int y2,
+ int x,
+ gboolean last);
+
+void
+draw_arrow (GdkWindow *window,
+ GdkGC *gc,
+ GdkRectangle *area,
+ GtkArrowType arrow_type,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+
+void
+calculate_arrow_geometry (GtkArrowType arrow_type,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height);
+
+GtkWidget *special_get_ancestor(GtkWidget * widget,
+ GType widget_type);
+
+void blend (GdkColormap *colormap,
+ GdkColor *a, GdkColor *b, GdkColor *c, int alpha);
+
+GtkWidget *get_parent_window (GtkWidget *widget);
+
+GdkColor *get_parent_bgcolor (GtkWidget *widget);
+
+gboolean is_combo_box (GtkWidget * widget);
+
+GtkWidget *find_combo_box_widget (GtkWidget * widget);
+
+void gtk_clist_get_header_index (GtkCList *clist, GtkWidget *button,
+ gint *column_index, gint *columns);
diff --git a/libs/fst/SConscript b/libs/fst/SConscript
index 2cbfb94a9f..771de86dc8 100644
--- a/libs/fst/SConscript
+++ b/libs/fst/SConscript
@@ -2,6 +2,7 @@
import os
import os.path
+import sys
import glob
fst_src = glob.glob('*.c')
@@ -22,7 +23,12 @@ c = fst.Object ('vstwin', 'vstwin.c')
d = fst.Object ('vsti', 'vsti.c')
if fst['VST']:
- Default([hackSDK,a,b,c,d])
+ if os.access ('vst/aeffectx.h', os.F_OK):
+ Default([hackSDK,a,b,c,d])
+ else:
+ print 'You have not installed the VST SDK in the correct location.'
+ print 'Please see http://ardour.org/building_vst_support for more information'
+ sys.exit (1)
env.Alias('tarball', env.Distribute (env['DISTTREE'],
fst_src + ['SConscript',
diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript
index cf513eb5a1..e654b6cb52 100644
--- a/libs/gtkmm2ext/SConscript
+++ b/libs/gtkmm2ext/SConscript
@@ -55,7 +55,7 @@ utils.cc
version.cc
""")
-gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], 'SConscript')
+gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], [])
gtkmm2ext.Append(CCFLAGS="-D_REENTRANT")
gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc
index eefe6ca843..734c4b77e2 100644
--- a/libs/gtkmm2ext/barcontroller.cc
+++ b/libs/gtkmm2ext/barcontroller.cc
@@ -423,6 +423,7 @@ BarController::switch_to_spinner ()
remove ();
add (spinner);
spinner.show ();
+ spinner.select_region (0, spinner.get_text_length());
spinner.grab_focus ();
switching = false;
diff --git a/libs/gtkmm2ext/click_box.cc b/libs/gtkmm2ext/click_box.cc
index efce988c29..3ab7ea883c 100644
--- a/libs/gtkmm2ext/click_box.cc
+++ b/libs/gtkmm2ext/click_box.cc
@@ -38,17 +38,18 @@ ClickBox::ClickBox (Gtk::Adjustment *adjp, const string &name, bool round_to_ste
twidth = 0;
theight = 0;
- set_name (name);
+
add_events (Gdk::BUTTON_RELEASE_MASK|
Gdk::BUTTON_PRESS_MASK|
Gdk::ENTER_NOTIFY_MASK|
Gdk::LEAVE_NOTIFY_MASK);
- set_label ();
get_adjustment().signal_value_changed().connect (mem_fun (*this, &ClickBox::set_label));
-
+ signal_style_changed().connect (mem_fun (*this, &ClickBox::style_changed));
signal_button_press_event().connect (mem_fun (*this, &ClickBox::button_press_handler));
signal_button_release_event().connect (mem_fun (*this, &ClickBox::button_release_handler));
+ set_name (name);
+ set_label ();
}
ClickBox::~ClickBox ()
@@ -102,6 +103,14 @@ ClickBox::set_label ()
queue_draw ();
}
+void
+ClickBox::style_changed (const Glib::RefPtr<Gtk::Style>& ignored)
+{
+
+ layout->context_changed ();
+ layout->get_pixel_size (twidth, theight);
+}
+
bool
ClickBox::on_expose_event (GdkEventExpose *ev)
{
@@ -136,7 +145,7 @@ ClickBox::on_expose_event (GdkEventExpose *ev)
win->draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
if (twidth && theight) {
- win->draw_layout (fg_gc, width - (twidth + 2), (height - theight) + 2, layout);
+ win->draw_layout (fg_gc, (width - twidth) / 2, (height - theight) / 2, layout);
}
}
diff --git a/libs/gtkmm2ext/gtkmm2ext/click_box.h b/libs/gtkmm2ext/gtkmm2ext/click_box.h
index c6f2922f3f..e4aee36ebe 100644
--- a/libs/gtkmm2ext/gtkmm2ext/click_box.h
+++ b/libs/gtkmm2ext/gtkmm2ext/click_box.h
@@ -54,6 +54,7 @@ class ClickBox : public Gtk::DrawingArea, public AutoSpin
int theight;
void set_label ();
+ void style_changed (const Glib::RefPtr<Gtk::Style> &);
bool button_press_handler (GdkEventButton *);
bool button_release_handler (GdkEventButton *);
diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
index 14af137680..a692e64c9c 100644
--- a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
+++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
@@ -101,6 +101,8 @@ class UI : public Receiver, public AbstractUI<UIRequest>
bool caller_is_ui_thread ();
+ static pthread_t thread_id() { return gui_thread; }
+
/* Gtk-UI specific interfaces */
bool running ();
diff --git a/libs/gtkmm2ext/tearoff.cc b/libs/gtkmm2ext/tearoff.cc
index 529cca15e3..e4a9207195 100644
--- a/libs/gtkmm2ext/tearoff.cc
+++ b/libs/gtkmm2ext/tearoff.cc
@@ -109,7 +109,7 @@ TearOff::tearoff_click (GdkEventButton* ev)
own_window.show_all ();
hide ();
Detach ();
- return TRUE;
+ return true;
}
gint
@@ -121,19 +121,25 @@ TearOff::close_click (GdkEventButton* ev)
own_window.hide ();
show_all ();
Attach ();
- return TRUE;
+ return true;
}
gint
TearOff::window_button_press (GdkEventButton* ev)
{
+ if (dragging) {
+ dragging = false;
+ own_window.remove_modal_grab();
+ return true;
+ }
+
dragging = true;
drag_x = ev->x_root;
drag_y = ev->y_root;
own_window.add_modal_grab();
- return TRUE;
+ return true;
}
gint
@@ -141,7 +147,7 @@ TearOff::window_button_release (GdkEventButton* ev)
{
dragging = false;
own_window.remove_modal_grab();
- return TRUE;
+ return true;
}
gint
@@ -163,7 +169,7 @@ TearOff::window_motion (GdkEventMotion* ev)
own_window.get_pointer (mx, my);
if (!dragging) {
- return TRUE;
+ return true;
}
x_delta = ev->x_root - drag_x;
@@ -175,7 +181,7 @@ TearOff::window_motion (GdkEventMotion* ev)
drag_x = ev->x_root;
drag_y = ev->y_root;
- return TRUE;
+ return true;
}
bool
diff --git a/libs/libsndfile/SConscript b/libs/libsndfile/SConscript
index b1c29e5487..f8e9fc5ecb 100644
--- a/libs/libsndfile/SConscript
+++ b/libs/libsndfile/SConscript
@@ -25,7 +25,7 @@ if conf.CheckCHeader('/System/Library/Frameworks/CoreServices.framework/Headers/
sndfile = conf.Finish()
-libsndfile = sndfile.SharedLibrary('sndfile', sndfile_files)
+libsndfile = sndfile.SharedLibrary('sndfile-ardour', sndfile_files)
sndfile_h = sndfile.Command('src/sndfile.h', ['src/sndfile.h.in'], 'cd libs/libsndfile && ./configure && cd -', ENV=os.environ)
diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript
index 65d0882dce..477d49c6ca 100644
--- a/libs/midi++2/SConscript
+++ b/libs/midi++2/SConscript
@@ -51,7 +51,7 @@ elif env['SYSMIDI'] == 'CoreMIDI':
midi2.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
midi2.Append(CCFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
-midi2.VersionBuild(['version.cc','midi++/version.h'], 'SConscript')
+midi2.VersionBuild(['version.cc','midi++/version.h'], [])
libmidi2 = midi2.SharedLibrary('midi++', [ sources, sysdep_src ])
diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h
index e29d7543f8..1d5c7e0b30 100644
--- a/libs/midi++2/midi++/factory.h
+++ b/libs/midi++2/midi++/factory.h
@@ -30,9 +30,8 @@ namespace MIDI {
class PortFactory {
public:
Port *create_port (PortRequest &req, void* data);
-
- static void add_port_request (std::vector<PortRequest *> &reqs,
- const std::string &reqstr);
+
+ static bool ignore_duplicate_devices (Port::Type);
};
} // namespace MIDI
diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc
index d8119e362e..de4a246bcf 100644
--- a/libs/midi++2/midifactory.cc
+++ b/libs/midi++2/midifactory.cc
@@ -89,20 +89,28 @@ PortFactory::create_port (PortRequest &req, void* data)
return port;
}
-void
-PortFactory::add_port_request (vector<PortRequest *> &reqs,
- const string &str)
-
+bool
+PortFactory::ignore_duplicate_devices (Port::Type type)
{
- PortRequest *req;
+ bool ret = false;
- req = new PortRequest;
- req->devname = strdup (str.c_str());
- req->tagname = strdup (str.c_str());
+ switch (type) {
+#ifdef WITH_ALSA
+ case Port::ALSA_Sequencer:
+ ret = true;
+ break;
+#endif // WITH_ALSA
- req->mode = O_RDWR;
- req->type = Port::ALSA_RawMidi;
+#if WITH_COREMIDI
+ case Port::CoreMidi_MidiPort:
+ ret = true;
+ break;
+#endif // WITH_COREMIDI
+
+ default:
+ break;
+ }
- reqs.push_back (req);
+ return ret;
}
diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc
index bfe8f147b6..970674232d 100644
--- a/libs/midi++2/midimanager.cc
+++ b/libs/midi++2/midimanager.cc
@@ -66,41 +66,43 @@ Manager::add_port (PortRequest &req)
PortMap::iterator existing;
pair<string, Port *> newpair;
- if ((existing = ports_by_device.find (req.devname)) !=
- ports_by_device.end()) {
-
- port = (*existing).second;
- if (port->mode() == req.mode) {
+ if (!PortFactory::ignore_duplicate_devices (req.type)) {
+
+ if ((existing = ports_by_device.find (req.devname)) != ports_by_device.end()) {
+
+ port = (*existing).second;
+
+ if (port->mode() == req.mode) {
+
+ /* Same mode - reuse the port, and just
+ create a new tag entry.
+ */
+
+ newpair.first = req.tagname;
+ newpair.second = port;
+
+ ports_by_tag.insert (newpair);
+ return port;
+ }
- /* Same mode - reuse the port, and just
- create a new tag entry.
+ /* If the existing is duplex, and this request
+ is not, then fail, because most drivers won't
+ allow opening twice with duplex and non-duplex
+ operation.
*/
-
- newpair.first = req.tagname;
- newpair.second = port;
-
- ports_by_tag.insert (newpair);
- return port;
- }
-
- /* If the existing is duplex, and this request
- is not, then fail, because most drivers won't
- allow opening twice with duplex and non-duplex
- operation.
- */
-
- if ((req.mode == O_RDWR && port->mode() != O_RDWR) ||
- (req.mode != O_RDWR && port->mode() == O_RDWR)) {
- error << "MIDIManager: port tagged \""
- << req.tagname
- << "\" cannot be opened duplex and non-duplex"
- << endmsg;
- return 0;
+
+ if ((req.mode == O_RDWR && port->mode() != O_RDWR) ||
+ (req.mode != O_RDWR && port->mode() == O_RDWR)) {
+ error << "MIDIManager: port tagged \""
+ << req.tagname
+ << "\" cannot be opened duplex and non-duplex"
+ << endmsg;
+ return 0;
+ }
+
+ /* modes must be different or complementary */
}
-
- /* modes must be different or complementary */
}
-
port = factory.create_port (req, api_data);
if (port == 0) {
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index 4b15dd70d1..f474834fd8 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -55,7 +55,7 @@ pbd.Merge ([ libraries['sigc2'],
libraries['glibmm2'],
libraries['glib2'] ])
-pbd.VersionBuild(['version.cc','pbd/version.h'], 'SConscript')
+pbd.VersionBuild(['version.cc','pbd/version.h'], [])
libpbd = pbd.SharedLibrary('pbd', pbd_files)
Default(libpbd)
diff --git a/libs/pbd/controllable.cc b/libs/pbd/controllable.cc
index 80c6811e6a..2264a955ae 100644
--- a/libs/pbd/controllable.cc
+++ b/libs/pbd/controllable.cc
@@ -6,7 +6,7 @@
using namespace PBD;
-sigc::signal<void,Controllable*> Controllable::GoingAway;
+sigc::signal<void,Controllable*> Controllable::Destroyed;
sigc::signal<bool,Controllable*> Controllable::StartLearning;
sigc::signal<void,Controllable*> Controllable::StopLearning;
diff --git a/libs/pbd/convert.cc b/libs/pbd/convert.cc
index 60d39c91e2..832c54acd8 100644
--- a/libs/pbd/convert.cc
+++ b/libs/pbd/convert.cc
@@ -19,6 +19,10 @@
#include <cmath>
#include <stdint.h>
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+#include <inttypes.h>
#include "pbd/convert.h"
@@ -106,12 +110,12 @@ atof (const string& s)
}
vector<string>
-internationalize (const char **array)
+internationalize (const char *package_name, const char **array)
{
vector<string> v;
for (uint32_t i = 0; array[i]; ++i) {
- v.push_back (_(array[i]));
+ v.push_back (dgettext(package_name, array[i]));
}
return v;
@@ -190,23 +194,44 @@ url_decode (string& url)
}
}
+#if 0
string
length2string (const int32_t frames, const float sample_rate)
{
- int secs = (int) (frames / sample_rate);
- int hrs = secs / 3600;
+ int32_t secs = (int32_t) (frames / sample_rate);
+ int32_t hrs = secs / 3600;
secs -= (hrs * 3600);
- int mins = secs / 60;
+ int32_t mins = secs / 60;
secs -= (mins * 60);
- int total_secs = (hrs * 3600) + (mins * 60) + secs;
- int frames_remaining = (int) floor (frames - (total_secs * sample_rate));
+ int32_t total_secs = (hrs * 3600) + (mins * 60) + secs;
+ int32_t frames_remaining = (int) floor (frames - (total_secs * sample_rate));
float fractional_secs = (float) frames_remaining / sample_rate;
char duration_str[32];
- sprintf (duration_str, "%02d:%02d:%05.2f", hrs, mins, (float) secs + fractional_secs);
+ sprintf (duration_str, "%02" PRIi32 ":%02" PRIi32 ":%05.2f", hrs, mins, (float) secs + fractional_secs);
return duration_str;
}
+#endif
+
+string
+length2string (const int64_t frames, const double sample_rate)
+{
+ int64_t secs = (int64_t) floor (frames / sample_rate);
+ int64_t hrs = secs / 3600LL;
+ secs -= (hrs * 3600LL);
+ int64_t mins = secs / 60LL;
+ secs -= (mins * 60LL);
+
+ int64_t total_secs = (hrs * 3600LL) + (mins * 60LL) + secs;
+ int64_t frames_remaining = (int64_t) floor (frames - (total_secs * sample_rate));
+ float fractional_secs = (float) frames_remaining / sample_rate;
+
+ char duration_str[64];
+ sprintf (duration_str, "%02" PRIi64 ":%02" PRIi64 ":%05.2f", hrs, mins, (float) secs + fractional_secs);
+
+ return duration_str;
+}
} // namespace PBD
diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h
index 7c367e7462..8044b51a83 100644
--- a/libs/pbd/pbd/command.h
+++ b/libs/pbd/pbd/command.h
@@ -21,10 +21,9 @@
#ifndef __lib_pbd_command_h__
#define __lib_pbd_command_h__
-#include <pbd/stateful.h>
-#include <pbd/destructible.h>
+#include <pbd/statefuldestructible.h>
-class Command : public Stateful, public PBD::Destructible
+class Command : public PBD::StatefulDestructible
{
public:
virtual ~Command() {}
diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h
index ff8f8a9b52..c88eb298bc 100644
--- a/libs/pbd/pbd/controllable.h
+++ b/libs/pbd/pbd/controllable.h
@@ -6,17 +6,16 @@
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
-#include <pbd/stateful.h>
-#include <pbd/id.h>
+#include <pbd/statefuldestructible.h>
class XMLNode;
namespace PBD {
-class Controllable : public virtual sigc::trackable, public Stateful {
+class Controllable : public PBD::StatefulDestructible {
public:
Controllable (std::string name);
- virtual ~Controllable() { GoingAway (this); }
+ virtual ~Controllable() { Destroyed (this); }
virtual void set_value (float) = 0;
virtual float get_value (void) const = 0;
@@ -25,11 +24,11 @@ class Controllable : public virtual sigc::trackable, public Stateful {
sigc::signal<void> LearningFinished;
- static sigc::signal<void,Controllable*> GoingAway;
-
static sigc::signal<bool,PBD::Controllable*> StartLearning;
static sigc::signal<void,PBD::Controllable*> StopLearning;
+ static sigc::signal<void,Controllable*> Destroyed;
+
sigc::signal<void> Changed;
int set_state (const XMLNode&);
diff --git a/libs/pbd/pbd/convert.h b/libs/pbd/pbd/convert.h
index 12e63ba6fc..55006529ae 100644
--- a/libs/pbd/pbd/convert.h
+++ b/libs/pbd/pbd/convert.h
@@ -31,9 +31,10 @@ int atoi (const std::string&);
double atof (const std::string&);
void url_decode (std::string&);
-std::string length2string (const int32_t frames, const float sample_rate);
+// std::string length2string (const int32_t frames, const float sample_rate);
+std::string length2string (const int64_t frames, const double sample_rate);
-std::vector<std::string> internationalize (const char **);
+std::vector<std::string> internationalize (const char *, const char **);
} //namespace PBD
diff --git a/libs/pbd/pbd/crossthread.h b/libs/pbd/pbd/crossthread.h
new file mode 100644
index 0000000000..413dea024e
--- /dev/null
+++ b/libs/pbd/pbd/crossthread.h
@@ -0,0 +1,38 @@
+#ifndef __pbd__crossthread_h__
+#define __pbd__crossthread_h__
+
+#include <pbd/abstract_ui.h>
+#include <sigc++/sigc++.h>
+#include <pthread.h>
+
+template<class RequestType>
+void
+call_slot_from_thread_or_dispatch_it (pthread_t thread_id, AbstractUI<RequestType>& ui, sigc::slot<void> theSlot)
+{
+ /* when called, this function will determine whether the calling thread
+ is the same as thread specified by the first argument. if it is,
+ the we execute the slot. if not, we ask the interface given by the second
+ argument to call the slot.
+ */
+
+ if (pthread_self() == thread_id) {
+ theSlot ();
+ } else {
+ ui.call_slot (theSlot);
+ }
+}
+
+template<class RequestType>
+sigc::slot<void>
+crossthread_safe (pthread_t thread_id, AbstractUI<RequestType>& ui, sigc::slot<void> theSlot)
+{
+ /* this function returns a slot that will ensure that theSlot is either
+ called by the specified thread or passed to the interface via
+ AbstractUI::call_slot().
+ */
+
+ return sigc::bind (sigc::ptr_fun (call_slot_from_thread_or_dispatch_it<RequestType>),
+ thread_id, ui, theSlot);
+}
+
+#endif /* __pbd__crossthread_h__ */
diff --git a/libs/pbd/pbd/destructible.h b/libs/pbd/pbd/destructible.h
index 6692ff564c..7c50806334 100644
--- a/libs/pbd/pbd/destructible.h
+++ b/libs/pbd/pbd/destructible.h
@@ -5,14 +5,22 @@
namespace PBD {
-class Destructible : public virtual sigc::trackable {
- public:
- Destructible() {}
- virtual ~Destructible () {}
+/* be very very careful using this class. it does not inherit from sigc::trackable and thus
+ should only be used in multiple-inheritance situations involving another type
+ that does inherit from sigc::trackable (or sigc::trackable itself)
+*/
+class ThingWithGoingAway {
+ public:
+ virtual ~ThingWithGoingAway () {}
sigc::signal<void> GoingAway;
+};
+class Destructible : public sigc::trackable, public ThingWithGoingAway {
+ public:
+ virtual ~Destructible () {}
void drop_references () const { GoingAway(); }
+
};
}
diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h
index d42972d546..fe1aa8e7d0 100644
--- a/libs/pbd/pbd/memento_command.h
+++ b/libs/pbd/pbd/memento_command.h
@@ -28,19 +28,11 @@ using std::endl;
#include <pbd/command.h>
#include <pbd/stacktrace.h>
#include <pbd/xml++.h>
+#include <pbd/shiva.h>
+
#include <sigc++/slot.h>
#include <typeinfo>
-/* grrr, strict C++ says that static member functions are not C functions, but we also want
- to be able to pack this into a sigc::ptr_fun and not sigc::mem_fun, so we have to make
- it a genuine function rather than a member.
-*/
-
-static void object_death (Command* mc) {
- cerr << "\n\n\n---> OBJECT DEATH FIRED FOR " << mc << endl;
- delete mc;
-}
-
/** This command class is initialized with before and after mementos
* (from Stateful::get_state()), so undo becomes restoring the before
* memento, and redo is restoring the after memento.
@@ -55,8 +47,8 @@ class MementoCommand : public Command
XMLNode *after
)
: obj(object), before(before), after(after) {
- cerr << "MC @ " << this << " is a " << typeid (obj_T).name() << endl;
- obj.GoingAway.connect (sigc::bind (sigc::ptr_fun (object_death), static_cast<Command*>(this)));
+ /* catch destruction of the object */
+ new PBD::Shiva<obj_T,MementoCommand<obj_T> > (object, *this);
}
~MementoCommand () {
diff --git a/libs/pbd/pbd/rcu.h b/libs/pbd/pbd/rcu.h
index e81db8ba87..a8f3cdd5bc 100644
--- a/libs/pbd/pbd/rcu.h
+++ b/libs/pbd/pbd/rcu.h
@@ -17,7 +17,7 @@ class RCUManager
virtual ~RCUManager() { delete m_rcu_value; }
- boost::shared_ptr<T> reader () const { return *((boost::shared_ptr<T> *) g_atomic_pointer_get (&m_rcu_value)); }
+ boost::shared_ptr<T> reader () const { return *((boost::shared_ptr<T> *) g_atomic_pointer_get (the_pointer())); }
virtual boost::shared_ptr<T> write_copy () = 0;
virtual bool update (boost::shared_ptr<T> new_value) = 0;
diff --git a/libs/pbd/pbd/shiva.h b/libs/pbd/pbd/shiva.h
index 5110f48332..53b613ea2b 100644
--- a/libs/pbd/pbd/shiva.h
+++ b/libs/pbd/pbd/shiva.h
@@ -5,28 +5,96 @@
namespace PBD {
-template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
-
/* named after the Hindu god Shiva, The Destroyer */
+template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
class Shiva {
public:
Shiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver) {
/* if the emitter goes away, destroy the receiver */
- _connection1 = emitter.GoingAway.connect
+ _connection = emitter.GoingAway.connect
(sigc::bind (sigc::mem_fun
(*this, &Shiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
&receiver));
+ }
+
+ ~Shiva() {
+ forget ();
+ }
+
+ private:
+ sigc::connection _connection;
+
+ void destroy (ObjectToBeDestroyed* obj) {
+ delete obj;
+ forget ();
+ }
+
+ void forget () {
+ _connection.disconnect ();
+ }
+
+};
+
+template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
+class ProxyShiva {
+ public:
+ ProxyShiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver, void (*callback)(ObjectToBeDestroyed*, ObjectWithGoingAway*)) {
+
+ /* if the emitter goes away, destroy the receiver */
+
+ _callback = callback;
+ _callback_argument1 = &receiver;
+ _callback_argument2 = &emitter;
+
+ _connection = emitter.GoingAway.connect
+ (sigc::bind (sigc::mem_fun
+ (*this, &ProxyShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
+ &receiver));
+ }
+
+ ~ProxyShiva() {
+ forget ();
+ }
+
+ private:
+ sigc::connection _connection;
+ void (*_callback) (ObjectToBeDestroyed*, ObjectWithGoingAway*);
+ ObjectToBeDestroyed* _callback_argument1;
+ ObjectWithGoingAway* _callback_argument2;
+
+ void destroy (ObjectToBeDestroyed* obj) {
+ /* callback must destroy obj if appropriate, not done here */
+ _callback (obj, _callback_argument2);
+ forget ();
+ }
+
+ void forget () {
+ _connection.disconnect ();
+ }
+};
+
+template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
+class PairedShiva {
+ public:
+ PairedShiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver) {
+
+ /* if the emitter goes away, destroy the receiver */
+
+ _connection1 = emitter.GoingAway.connect
+ (sigc::bind (sigc::mem_fun
+ (*this, &PairedShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
+ &receiver));
/* if the receiver goes away, forget all this nonsense */
_connection2 = receiver.GoingAway.connect
- (sigc::mem_fun (*this, &Shiva<ObjectWithGoingAway,ObjectToBeDestroyed>::forget));
+ (sigc::mem_fun (*this, &PairedShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::forget));
}
- ~Shiva() {
+ ~PairedShiva() {
forget ();
}
diff --git a/libs/pbd/pbd/statefuldestructible.h b/libs/pbd/pbd/statefuldestructible.h
index e78cc4bdaa..708c10fc8e 100644
--- a/libs/pbd/pbd/statefuldestructible.h
+++ b/libs/pbd/pbd/statefuldestructible.h
@@ -5,9 +5,21 @@
#include <pbd/destructible.h>
namespace PBD {
+
class StatefulDestructible : public Stateful, public Destructible
{
};
+
+/* be very very careful using this class. it does not inherit from sigc::trackable and thus
+ should only be used in multiple-inheritance situations involving another type
+ that does inherit from sigc::trackable (or sigc::trackable itself)
+*/
+
+class StatefulThingWithGoingAway : public Stateful, public ThingWithGoingAway
+{
+};
+
}
+
#endif /* __pbd_stateful_destructible_h__ */
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
index 943c115af2..eb46750e4f 100644
--- a/libs/pbd/pbd/undo.h
+++ b/libs/pbd/pbd/undo.h
@@ -70,9 +70,11 @@ class UndoTransaction : public Command
struct timeval _timestamp;
std::string _name;
bool _clearing;
+
+ friend void command_death (UndoTransaction*, Command *);
};
-class UndoHistory
+class UndoHistory : public sigc::trackable
{
public:
UndoHistory();
@@ -95,6 +97,8 @@ class UndoHistory
XMLNode &get_state();
void save_state();
+ sigc::signal<void> Changed;
+
private:
bool _clearing;
std::list<UndoTransaction*> UndoList;
diff --git a/libs/pbd/pbd/xml++.h b/libs/pbd/pbd/xml++.h
index 5dcb4f084a..70e231e717 100644
--- a/libs/pbd/pbd/xml++.h
+++ b/libs/pbd/pbd/xml++.h
@@ -87,9 +87,10 @@ public:
const string & set_content (const string &);
XMLNode *add_content(const string & = string());
- const XMLNodeList & children (const string & = string()) const;
+ const XMLNodeList & children (const string& str = string()) const;
XMLNode *add_child (const char *);
XMLNode *add_child_copy (const XMLNode&);
+ XMLNode *child (const char*) const;
void add_child_nocopy (XMLNode&);
const XMLPropertyList & properties() const { return _proplist; };
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc
index af408a24a4..277b83bfce 100644
--- a/libs/pbd/undo.cc
+++ b/libs/pbd/undo.cc
@@ -24,31 +24,13 @@
#include <pbd/undo.h>
#include <pbd/xml++.h>
+#include <pbd/shiva.h>
#include <sigc++/bind.h>
using namespace std;
using namespace sigc;
-/* grrr, strict C++ says that static member functions are not C functions, but we also want
- to be able to pack this into a sigc::ptr_fun and not sigc::mem_fun, so we have to make
- it a genuine function rather than a member.
-*/
-
-static void command_death (UndoTransaction* ut, Command* c)
-{
- if (ut->clearing()) {
- return;
- }
-
- ut->remove_command (c);
-
- if (ut->empty()) {
- delete ut;
- }
-}
-
-
UndoTransaction::UndoTransaction ()
{
_clearing = false;
@@ -68,6 +50,20 @@ UndoTransaction::~UndoTransaction ()
clear ();
}
+void
+command_death (UndoTransaction* ut, Command* c)
+{
+ if (ut->clearing()) {
+ return;
+ }
+
+ ut->remove_command (c);
+
+ if (ut->empty()) {
+ delete ut;
+ }
+}
+
UndoTransaction&
UndoTransaction::operator= (const UndoTransaction& rhs)
{
@@ -81,7 +77,8 @@ UndoTransaction::operator= (const UndoTransaction& rhs)
void
UndoTransaction::add_command (Command *const action)
{
- action->GoingAway.connect (bind (sigc::ptr_fun (command_death), this, const_cast<Command*>(action)));
+ /* catch death */
+ new PBD::ProxyShiva<Command,UndoTransaction> (*action, *this, &command_death);
actions.push_back (action);
}
@@ -160,6 +157,8 @@ UndoHistory::add (UndoTransaction* const ut)
UndoList.push_back (ut);
/* we are now owners of the transaction */
+
+ Changed (); /* EMIT SIGNAL */
}
void
@@ -171,6 +170,8 @@ UndoHistory::remove (UndoTransaction* const ut)
UndoList.remove (ut);
RedoList.remove (ut);
+
+ Changed (); /* EMIT SIGNAL */
}
void
@@ -185,6 +186,8 @@ UndoHistory::undo (unsigned int n)
ut->undo ();
RedoList.push_back (ut);
}
+
+ Changed (); /* EMIT SIGNAL */
}
void
@@ -199,6 +202,8 @@ UndoHistory::redo (unsigned int n)
ut->redo ();
UndoList.push_back (ut);
}
+
+ Changed (); /* EMIT SIGNAL */
}
void
@@ -207,6 +212,9 @@ UndoHistory::clear_redo ()
_clearing = true;
RedoList.clear ();
_clearing = false;
+
+ Changed (); /* EMIT SIGNAL */
+
}
void
@@ -215,6 +223,8 @@ UndoHistory::clear_undo ()
_clearing = true;
UndoList.clear ();
_clearing = false;
+
+ Changed (); /* EMIT SIGNAL */
}
void
@@ -222,6 +232,8 @@ UndoHistory::clear ()
{
clear_undo ();
clear_redo ();
+
+ Changed (); /* EMIT SIGNAL */
}
XMLNode & UndoHistory::get_state()
diff --git a/libs/pbd/whitespace.cc b/libs/pbd/whitespace.cc
index e35a8a8c0e..53616133ad 100644
--- a/libs/pbd/whitespace.cc
+++ b/libs/pbd/whitespace.cc
@@ -11,6 +11,10 @@ strip_whitespace_edges (string& str)
len = str.length();
+ if (len == 1) {
+ return;
+ }
+
/* strip front */
for (i = 0; i < len; ++i) {
@@ -19,12 +23,21 @@ strip_whitespace_edges (string& str)
}
}
+ if (i == len) {
+ /* its all whitespace, not much we can do */
+ return;
+ }
+
/* strip back */
if (len > 1) {
s = i;
i = len - 1;
+
+ if (s == i) {
+ return;
+ }
do {
if (isgraph (str[i]) || i == 0) {
diff --git a/libs/pbd/xml++.cc b/libs/pbd/xml++.cc
index 03fa116279..8d783d59f2 100644
--- a/libs/pbd/xml++.cc
+++ b/libs/pbd/xml++.cc
@@ -110,7 +110,7 @@ XMLTree::write(void) const
doc = xmlNewDoc((xmlChar *) "1.0");
xmlSetDocCompressMode(doc, _compression);
writenode(doc, _root, doc->children, 1);
- result = xmlSaveFormatFile(_filename.c_str(), doc, 1);
+ result = xmlSaveFormatFileEnc(_filename.c_str(), doc, "UTF-8", 1);
xmlFreeDoc(doc);
if (result == -1) {
@@ -216,13 +216,35 @@ XMLNode::set_content(const string & c)
return _content;
}
+XMLNode*
+XMLNode::child (const char *name) const
+{
+ /* returns first child matching name */
+
+ XMLNodeConstIterator cur;
+
+ if (name == 0) {
+ return 0;
+ }
+
+ for (cur = _children.begin(); cur != _children.end(); ++cur) {
+ if ((*cur)->name() == name) {
+ return *cur;
+ }
+ }
+
+ return 0;
+}
+
const XMLNodeList &
-XMLNode::children(const string & n) const
+XMLNode::children(const string& n) const
{
+ /* returns all children matching name */
+
static XMLNodeList retval;
XMLNodeConstIterator cur;
- if (n.length() == 0) {
+ if (n.empty()) {
return _children;
}
diff --git a/libs/surfaces/control_protocol/SConscript b/libs/surfaces/control_protocol/SConscript
index ce59b1c67c..88aeeda376 100644
--- a/libs/surfaces/control_protocol/SConscript
+++ b/libs/surfaces/control_protocol/SConscript
@@ -33,6 +33,7 @@ cp.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
cp.Merge ([
libraries['ardour'],
+ libraries['sndfile-ardour'],
libraries['sigc2'],
libraries['pbd'],
libraries['midi++2'],
diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc
index 07e000ab20..e6642d3394 100644
--- a/libs/surfaces/control_protocol/basic_ui.cc
+++ b/libs/surfaces/control_protocol/basic_ui.cc
@@ -55,7 +55,7 @@ BasicUI::register_thread (std::string name)
void
BasicUI::loop_toggle ()
{
- if (Config->get_auto_loop()) {
+ if (session->get_play_loop()) {
session->request_play_loop (false);
} else {
session->request_play_loop (true);
@@ -107,7 +107,7 @@ BasicUI::transport_play (bool from_last_start)
{
bool rolling = session->transport_rolling ();
- if (Config->get_auto_loop()) {
+ if (session->get_play_loop()) {
session->request_play_loop (false);
}
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc
index 2e2d943244..ea85a32a77 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc
@@ -718,7 +718,7 @@ TranzportControlProtocol::update_state ()
/* global */
- if (Config->get_auto_loop()) {
+ if (session->get_play_loop()) {
pending_lights[LightLoop] = true;
} else {
pending_lights[LightLoop] = false;
@@ -760,6 +760,14 @@ TranzportControlProtocol::update_state ()
}
}
+ if (pending_lights[LightTrackrec] != lights[LightTrackrec]) {
+ if (pending_lights[LightTrackrec]) {
+ light_on (LightTrackrec);
+ } else {
+ light_off (LightTrackrec);
+ }
+ }
+
if (pending_lights[LightTrackmute] != lights[LightTrackmute]) {
if (pending_lights[LightTrackmute]) {
light_on (LightTrackmute);