Compare commits
42 Commits
a2015c9ced
...
f9498a667f
Author | SHA1 | Date | |
---|---|---|---|
f9498a667f | |||
00c6aed6cf | |||
bd89fb54c0 | |||
f10f5b35d1 | |||
5446eae928 | |||
0910fe1a6b | |||
adc9d9e0af | |||
|
07c79ce92c | ||
44b2377e72 | |||
4fc4a2ca09 | |||
ca7ac7027b | |||
22a2cb0624 | |||
1aad6805b3 | |||
dab22a7c70 | |||
ed437afda7 | |||
11f71a3297 | |||
d60e0e7ade | |||
c6ef4c3545 | |||
46f61d7662 | |||
6b5582deef | |||
28605b5351 | |||
1d921dec0b | |||
2014faaeca | |||
dd4a1a6d73 | |||
72deb74c58 | |||
395833e4f8 | |||
0b5a197f76 | |||
d089f38481 | |||
dcd79f3135 | |||
aeb4f925c6 | |||
e8c67408bb | |||
e8445d13ec | |||
88a24ae8e5 | |||
538a8cbccc | |||
6a741689d1 | |||
8d3ebde60e | |||
c4fdd5356c | |||
301777e7fe | |||
71a3161252 | |||
3751d20ce9 | |||
d8e4e7b259 | |||
9945d7721f |
@ -758,7 +758,7 @@ ARDOUR_UI::check_memory_locking ()
|
||||
|
||||
XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
|
||||
|
||||
if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
|
||||
if (memory_warning_node == 0) {
|
||||
|
||||
struct rlimit limits;
|
||||
int64_t ram;
|
||||
|
@ -84,6 +84,10 @@ EditorSnapshots::button_press (GdkEventButton* ev)
|
||||
int cx;
|
||||
int cy;
|
||||
_snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
_snapshot_display.get_selection()->select (path);
|
||||
Gtk::TreeModel::iterator iter = _snapshot_model->get_iter (path);
|
||||
if (iter) {
|
||||
Gtk::TreeModel::Row row = *iter;
|
||||
@ -97,6 +101,9 @@ EditorSnapshots::button_press (GdkEventButton* ev)
|
||||
int cy;
|
||||
string snap_name;
|
||||
_snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
Gtk::TreeModel::iterator iter = _snapshot_model->get_iter (path);
|
||||
if (iter) {
|
||||
Gtk::TreeModel::Row row = *iter;
|
||||
|
@ -89,7 +89,7 @@ InsertRemoveTimeDialog::InsertRemoveTimeDialog (PublicEditor& e, bool remove)
|
||||
_intersected_combo.append (_("stay in position"));
|
||||
_intersected_combo.append (_("move"));
|
||||
_intersected_combo.append (_("be split"));
|
||||
_intersected_combo.set_active (0);
|
||||
_intersected_combo.set_active (2);
|
||||
table->attach (_intersected_combo, 1, 2, 2, 3);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <glib.h>
|
||||
#include <glibmm/timer.h>
|
||||
@ -42,7 +41,6 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct ERect{
|
||||
@ -319,9 +317,8 @@ any Xevents to all the UI callbacks plugins 'may' have registered on their
|
||||
windows, that is if they don't manage their own UIs **/
|
||||
|
||||
static void*
|
||||
gui_event_loop (void* ptr)
|
||||
gui_event_loop (void*)
|
||||
{
|
||||
pthread_set_name ("LXVSTEventLoop");
|
||||
VSTState* vstfx;
|
||||
int LXVST_sched_timer_interval = 40; //ms, 25fps
|
||||
XEvent event;
|
||||
@ -509,20 +506,6 @@ int vstfx_init (void* ptr)
|
||||
assert (gui_state == -1);
|
||||
pthread_mutex_init (&plugin_mutex, NULL);
|
||||
|
||||
int thread_create_result;
|
||||
|
||||
pthread_attr_t thread_attributes;
|
||||
|
||||
/*Init the attribs to defaults*/
|
||||
|
||||
pthread_attr_init (&thread_attributes);
|
||||
|
||||
/*Make sure the thread is joinable - this should be the default anyway -
|
||||
so we can join to it on vstfx_exit*/
|
||||
|
||||
pthread_attr_setdetachstate (&thread_attributes, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
|
||||
/*This is where we need to open a connection to X, and start the GUI thread*/
|
||||
|
||||
/*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
|
||||
@ -546,7 +529,7 @@ int vstfx_init (void* ptr)
|
||||
|
||||
/*Create the thread - use default attrs for now, don't think we need anything special*/
|
||||
|
||||
thread_create_result = pthread_create (&LXVST_gui_event_thread, &thread_attributes, gui_event_loop, NULL);
|
||||
int thread_create_result = pthread_create_and_store ("LXVSTEventLoop", &LXVST_gui_event_thread, gui_event_loop, NULL, 0);
|
||||
|
||||
if (thread_create_result != 0)
|
||||
{
|
||||
|
@ -97,7 +97,6 @@ build_query_string (ArdourCurl::HttpGet const & h)
|
||||
static void*
|
||||
_pingback (void *arg)
|
||||
{
|
||||
pthread_set_name ("Pingback");
|
||||
ArdourCurl::HttpGet h;
|
||||
|
||||
//initialize curl
|
||||
@ -177,7 +176,7 @@ void pingback (const string& version, const string& announce_path)
|
||||
ping_call* cm = new ping_call (version, announce_path);
|
||||
pthread_t thread;
|
||||
|
||||
pthread_create_and_store ("pingback", &thread, _pingback, cm);
|
||||
pthread_create_and_store ("Pingback", &thread, _pingback, cm);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1310,7 +1310,6 @@ RouteTimeAxisView::find_next_region_boundary (timepos_t const & pos, int32_t dir
|
||||
void
|
||||
RouteTimeAxisView::fade_range (TimeSelection& selection)
|
||||
{
|
||||
std::shared_ptr<Playlist> what_we_got;
|
||||
std::shared_ptr<Track> tr = track ();
|
||||
std::shared_ptr<Playlist> playlist;
|
||||
|
||||
@ -1328,11 +1327,7 @@ RouteTimeAxisView::fade_range (TimeSelection& selection)
|
||||
|
||||
playlist->fade_range (time);
|
||||
|
||||
vector<Command*> cmds;
|
||||
playlist->rdiff (cmds);
|
||||
_session->add_commands (cmds);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
|
||||
playlist->rdiff_and_add_command (_session);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -132,7 +132,7 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
|
||||
/* Create a thread which runs while the dialogue is open to compute the silence regions */
|
||||
Completed.connect (_completed_connection, invalidator(*this), boost::bind (&StripSilenceDialog::update, this), gui_context ());
|
||||
_thread_should_finish = false;
|
||||
pthread_create (&_thread, 0, StripSilenceDialog::_detection_thread_work, this);
|
||||
pthread_create_and_store ("SilenceDetect", &_thread, StripSilenceDialog::_detection_thread_work, this, 0);
|
||||
|
||||
signal_response().connect(sigc::mem_fun (*this, &StripSilenceDialog::finished));
|
||||
}
|
||||
@ -248,7 +248,6 @@ void *
|
||||
StripSilenceDialog::_detection_thread_work (void* arg)
|
||||
{
|
||||
StripSilenceDialog* d = reinterpret_cast<StripSilenceDialog*> (arg);
|
||||
pthread_set_name ("SilenceDetect");
|
||||
return d->detection_thread_work ();
|
||||
}
|
||||
|
||||
|
@ -770,7 +770,9 @@ string
|
||||
ARDOUR_UI_UTILS::rate_as_string (float r)
|
||||
{
|
||||
char buf[32];
|
||||
if (fmod (r, 1000.0f)) {
|
||||
if (fmod (r, 100.0f)) {
|
||||
snprintf (buf, sizeof (buf), "%.2f kHz", r / 1000.0);
|
||||
} else if (fmod (r, 1000.0f)) {
|
||||
snprintf (buf, sizeof (buf), "%.1f kHz", r / 1000.0);
|
||||
} else {
|
||||
snprintf (buf, sizeof (buf), "%.0f kHz", r / 1000.0);
|
||||
|
@ -274,6 +274,8 @@ VideoImageFrame::http_get (samplepos_t fn) {
|
||||
queued_request=false;
|
||||
req_video_frame_number=fn;
|
||||
pthread_mutex_unlock(&queue_lock);
|
||||
/* do not use `pbd pthread_create_and_store' here.
|
||||
* The request thread uses aync cancellation */
|
||||
int rv = pthread_create(&thread_id_tt, NULL, http_get_thread, this);
|
||||
thread_active=true;
|
||||
if (rv) {
|
||||
|
@ -164,7 +164,7 @@ public:
|
||||
/** Return true if the backed is JACK */
|
||||
virtual bool is_jack () const { return false; }
|
||||
|
||||
virtual int client_real_time_priority () { return PBD_RT_PRI_PROC; }
|
||||
virtual int client_real_time_priority () { return 0; }
|
||||
|
||||
/* Discovering devices and parameters */
|
||||
|
||||
|
@ -115,9 +115,6 @@ class LIBARDOUR_API AudioEngine : public PortManager, public SessionHandlePtr
|
||||
void request_device_list_update();
|
||||
void launch_device_control_app();
|
||||
|
||||
int client_real_time_priority ();
|
||||
bool is_realtime() const;
|
||||
|
||||
// for the user which hold state_lock to check if reset operation is pending
|
||||
bool is_reset_requested() const { return _hw_reset_request_count.load(); }
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include "pbd/gstdio_compat.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "ardour/export_pointers.h"
|
||||
#include "ardour/session.h"
|
||||
@ -146,7 +147,13 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::tr
|
||||
|
||||
/* Timespan management */
|
||||
|
||||
static void* start_timespan_bg (void*);
|
||||
void timespan_thread_wakeup ();
|
||||
|
||||
static void* _timespan_thread_run (void*);
|
||||
PBD::Thread* _timespan_thread;
|
||||
std::atomic<int> _timespan_thread_active;
|
||||
pthread_mutex_t _timespan_mutex;
|
||||
pthread_cond_t _timespan_cond;
|
||||
|
||||
int start_timespan ();
|
||||
int process_timespan (samplecnt_t samples);
|
||||
|
@ -223,6 +223,7 @@ CONFIG_VARIABLE (bool, allow_special_bus_removal, "allow-special-bus-removal", f
|
||||
CONFIG_VARIABLE (int32_t, processor_usage, "processor-usage", -1)
|
||||
CONFIG_VARIABLE (int32_t, cpu_dma_latency, "cpu-dma-latency", -1) /* >=0 to enable */
|
||||
CONFIG_VARIABLE (int32_t, io_thread_count, "io-thread-count", -2)
|
||||
CONFIG_VARIABLE (int32_t, io_thread_policy, "io-thread-policy", 0)
|
||||
CONFIG_VARIABLE (gain_t, max_gain, "max-gain", 2.0) /* +6.0dB */
|
||||
CONFIG_VARIABLE (uint32_t, max_recent_sessions, "max-recent-sessions", 10)
|
||||
CONFIG_VARIABLE (uint32_t, max_recent_templates, "max-recent-templates", 10)
|
||||
|
@ -553,7 +553,7 @@ public:
|
||||
std::shared_ptr<AutomationControl> mapped_control (enum WellKnownCtrl, uint32_t band = 0) const;
|
||||
std::shared_ptr<ReadOnlyControl> mapped_output (enum WellKnownData) const;
|
||||
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const;
|
||||
std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const;
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const;
|
||||
|
@ -811,7 +811,7 @@ public:
|
||||
|
||||
double engine_speed() const { return _engine_speed; }
|
||||
double actual_speed() const;
|
||||
double transport_speed() const;
|
||||
double transport_speed (bool incl_preroll = false) const;
|
||||
/** @return true if the transport state (TFSM) is stopped */
|
||||
bool transport_stopped() const;
|
||||
/** @return true if the transport state (TFSM) is stopped or stopping */
|
||||
|
@ -158,7 +158,7 @@ class LIBARDOUR_API Stripable : public SessionObject,
|
||||
* In Ardour, these are user-created sends that connect to user-created
|
||||
* Aux busses.
|
||||
*/
|
||||
virtual std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const = 0;
|
||||
virtual std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const = 0;
|
||||
|
@ -134,7 +134,7 @@ class LIBARDOUR_API VCA : public Stripable,
|
||||
uint32_t eq_band_cnt () const { return 0; }
|
||||
std::string eq_band_name (uint32_t) const { return std::string(); }
|
||||
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_level_controllable (uint32_t n, bool locked = false) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_enable_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
std::shared_ptr<AutomationControl> send_pan_azimuth_enable_controllable (uint32_t n) const { return std::shared_ptr<AutomationControl>(); }
|
||||
|
@ -359,6 +359,10 @@ private:
|
||||
bool _no_kMono;
|
||||
/* work around yabridge threading */
|
||||
bool _restart_component_is_synced;
|
||||
/* work around PSL calls during set_owner,
|
||||
* while the route holds a processor lock
|
||||
*/
|
||||
std::atomic<bool> _in_set_owner;
|
||||
};
|
||||
|
||||
} // namespace Steinberg
|
||||
|
@ -678,7 +678,6 @@ void
|
||||
AudioEngine::do_reset_backend()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 1024);
|
||||
pthread_set_name ("EngineWatchdog");
|
||||
|
||||
Glib::Threads::Mutex::Lock guard (_reset_request_lock);
|
||||
|
||||
@ -739,7 +738,6 @@ void
|
||||
AudioEngine::do_devicelist_update()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
|
||||
pthread_set_name ("DeviceList");
|
||||
|
||||
Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
|
||||
|
||||
@ -769,13 +767,13 @@ AudioEngine::start_hw_event_processing()
|
||||
if (_hw_reset_event_thread == 0) {
|
||||
_hw_reset_request_count.store (0);
|
||||
_stop_hw_reset_processing.store (0);
|
||||
_hw_reset_event_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
|
||||
_hw_reset_event_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this), "EngineWatchdog");
|
||||
}
|
||||
|
||||
if (_hw_devicelist_update_thread == 0) {
|
||||
_hw_devicelist_update_count.store (0);
|
||||
_stop_hw_devicelist_processing.store (0);
|
||||
_hw_devicelist_update_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
|
||||
_hw_devicelist_update_thread = PBD::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this), "DeviceList");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,6 +1067,12 @@ AudioEngine::start (bool for_latency)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_backend->is_realtime ()) {
|
||||
pbd_set_engine_rt_priority (_backend->client_real_time_priority ());
|
||||
} else {
|
||||
pbd_set_engine_rt_priority (0);
|
||||
}
|
||||
|
||||
_running = true;
|
||||
|
||||
if (_session) {
|
||||
@ -1192,38 +1196,6 @@ AudioEngine::get_dsp_load() const
|
||||
return _backend->dsp_load ();
|
||||
}
|
||||
|
||||
bool
|
||||
AudioEngine::is_realtime() const
|
||||
{
|
||||
if (!_backend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _backend->is_realtime();
|
||||
}
|
||||
|
||||
int
|
||||
AudioEngine::client_real_time_priority ()
|
||||
{
|
||||
if (!_backend) {
|
||||
assert (0);
|
||||
return PBD_RT_PRI_PROC;
|
||||
}
|
||||
if (!_backend->is_realtime ()) {
|
||||
/* this is only an issue with the Dummy backend.
|
||||
* - with JACK, we require rt permissions.
|
||||
* - with ALSA/PulseAudio this can only happen if rt permissions
|
||||
* are n/a. Other attempts to get rt will fail likewise.
|
||||
*
|
||||
* perhaps:
|
||||
* TODO: use is_realtime () ? PBD_SCHED_FIFO : PBD_SCHED_OTHER
|
||||
*/
|
||||
return PBD_RT_PRI_PROC; // XXX
|
||||
}
|
||||
|
||||
return _backend->client_real_time_priority();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::transport_start ()
|
||||
{
|
||||
|
@ -234,9 +234,9 @@ AudioRegion::register_properties ()
|
||||
, _fade_before_fx (Properties::fade_before_fx, other->_fade_before_fx) \
|
||||
, _scale_amplitude (Properties::scale_amplitude, other->_scale_amplitude) \
|
||||
, _fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_in.val()))) \
|
||||
, _inverse_fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
, _fade_out (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_out.val()))) \
|
||||
, _inverse_fade_out (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_out.val())))
|
||||
, _inverse_fade_in (Properties::inverse_fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
, _fade_out (Properties::fade_out, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_out.val()))) \
|
||||
, _inverse_fade_out (Properties::inverse_fade_out, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_out.val())))
|
||||
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
||||
|
||||
void
|
||||
|
@ -423,10 +423,6 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
|
||||
* least large enough for all the data in the audio file. if it
|
||||
* is too short, assume that a crash or other error truncated
|
||||
* it, and rebuild it from scratch.
|
||||
*
|
||||
* XXX this may not work for destructive recording, but we
|
||||
* might decided to get rid of that anyway.
|
||||
*
|
||||
*/
|
||||
|
||||
const off_t expected_file_size = (_length.samples() / (double) samples_per_file_peak) * sizeof (PeakData);
|
||||
@ -591,10 +587,6 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
|
||||
samplecnt_t nvisual_peaks = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
/* handle the case where the initial visual peak is on a pixel boundary */
|
||||
|
||||
//current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
|
||||
|
||||
/* open ... close during out: handling */
|
||||
|
||||
off_t map_off = (uint32_t) (current_stored_peak) * sizeof(PeakData);
|
||||
|
@ -201,8 +201,7 @@ AutomationWatch::timer ()
|
||||
void
|
||||
AutomationWatch::thread ()
|
||||
{
|
||||
pbd_set_thread_priority (pthread_self(), PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority() - 2); // XXX
|
||||
pthread_set_name ("AutomationWatch");
|
||||
pbd_set_thread_priority (pthread_self(), PBD_SCHED_FIFO, PBD_RT_PRI_CTRL);
|
||||
while (_run_thread) {
|
||||
Glib::usleep ((gulong) floor (Config->get_automation_interval_msecs() * 1000)); // TODO use pthread_cond_timedwait on _run_thread
|
||||
timer ();
|
||||
@ -224,7 +223,7 @@ AutomationWatch::set_session (Session* s)
|
||||
|
||||
if (_session) {
|
||||
_run_thread = true;
|
||||
_thread = PBD::Thread::create (boost::bind (&AutomationWatch::thread, this));
|
||||
_thread = PBD::Thread::create (boost::bind (&AutomationWatch::thread, this), "AutomationWatch");
|
||||
|
||||
_session->TransportStateChange.connect_same_thread (transport_connection, boost::bind (&AutomationWatch::transport_state_change, this));
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ Butler::start_thread ()
|
||||
|
||||
should_run = false;
|
||||
|
||||
if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
|
||||
if (pthread_create_and_store ("butler", &thread, _thread_work, this)) {
|
||||
error << _("Session: could not create butler thread") << endmsg;
|
||||
return -1;
|
||||
}
|
||||
@ -171,7 +171,6 @@ void*
|
||||
Butler::_thread_work (void* arg)
|
||||
{
|
||||
SessionEvent::create_per_thread_pool ("butler events", 4096);
|
||||
pthread_set_name (X_("butler"));
|
||||
/* get thread buffers for RegionFx */
|
||||
ARDOUR::ProcessThread* pt = new ProcessThread ();
|
||||
pt->get_buffers ();
|
||||
|
@ -185,7 +185,7 @@ ControlProtocolManager::set_session (Session* s)
|
||||
usb_hotplug_cb, this,
|
||||
&_hpcp)) {
|
||||
_hotplug_thread_run = true;
|
||||
if (pthread_create (&_hotplug_thread, NULL, usb_hotplug_thread, this)) {
|
||||
if (pthread_create_and_store ("Ctrl USB Hotplug", &_hotplug_thread, usb_hotplug_thread, this, 0)) {
|
||||
_hotplug_thread_run = false;
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ Convolution::restart ()
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance ()->client_real_time_priority () - 1), PBD_SCHED_FIFO);
|
||||
rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, PBD_RT_PRI_PROC), PBD_SCHED_FIFO);
|
||||
}
|
||||
|
||||
assert (rv == 0); // bail out in debug builds
|
||||
|
@ -113,8 +113,9 @@ DiskReader::ReaderChannelInfo::resize_preloop (samplecnt_t bufsize)
|
||||
int
|
||||
DiskReader::add_channel_to (std::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler ()->audio_playback_buffer_size ());
|
||||
while (how_many--) {
|
||||
c->push_back (new ReaderChannelInfo (_session.butler ()->audio_playback_buffer_size (), loop_fade_length));
|
||||
c->push_back (new ReaderChannelInfo (bufsz, loop_fade_length));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("'%1': new reader channel, write space = %2 read = %3\n",
|
||||
name (),
|
||||
c->back ()->rbuf->write_space (),
|
||||
@ -236,8 +237,10 @@ DiskReader::adjust_buffering ()
|
||||
{
|
||||
std::shared_ptr<ChannelList const> c = channels.reader ();
|
||||
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler ()->audio_playback_buffer_size ());
|
||||
|
||||
for (auto const& chan : *c) {
|
||||
chan->resize (_session.butler ()->audio_playback_buffer_size ());
|
||||
chan->resize (bufsz);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,9 @@ DiskWriter::WriterChannelInfo::resize (samplecnt_t bufsize)
|
||||
int
|
||||
DiskWriter::add_channel_to (std::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler()->audio_capture_buffer_size());
|
||||
while (how_many--) {
|
||||
c->push_back (new WriterChannelInfo (_session.butler()->audio_capture_buffer_size()));
|
||||
c->push_back (new WriterChannelInfo (bufsz));
|
||||
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new writer channel, write space = %2 read = %3\n",
|
||||
name(),
|
||||
c->back()->wbuf->write_space(),
|
||||
@ -1386,8 +1387,9 @@ DiskWriter::adjust_buffering ()
|
||||
{
|
||||
std::shared_ptr<ChannelList const> c = channels.reader();
|
||||
|
||||
samplecnt_t bufsz = std::max<samplecnt_t> (_chunk_samples * 2, _session.butler()->audio_capture_buffer_size());
|
||||
for (auto const chan : *c) {
|
||||
chan->resize (_session.butler()->audio_capture_buffer_size());
|
||||
chan->resize (bufsz);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,15 @@ ExportHandler::ExportHandler (Session & session)
|
||||
, cue_tracknum (0)
|
||||
, cue_indexnum (0)
|
||||
{
|
||||
pthread_mutex_init (&_timespan_mutex, 0);
|
||||
pthread_cond_init (&_timespan_cond, 0);
|
||||
_timespan_thread_active.store (1);
|
||||
_timespan_thread = PBD::Thread::create (boost::bind (_timespan_thread_run, this), "ExportHandler");
|
||||
if (!_timespan_thread) {
|
||||
_timespan_thread_active.store (0);
|
||||
fatal << "Cannot create export handler helper thread" << endmsg;
|
||||
abort(); /* NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
ExportHandler::~ExportHandler ()
|
||||
@ -130,6 +139,51 @@ ExportHandler::~ExportHandler ()
|
||||
session.surround_master ()->surround_return ()->finalize_export ();
|
||||
}
|
||||
graph_builder->cleanup (export_status->aborted () );
|
||||
|
||||
pthread_mutex_lock (&_timespan_mutex);
|
||||
_timespan_thread_active.store (0);
|
||||
pthread_cond_signal (&_timespan_cond);
|
||||
pthread_mutex_unlock (&_timespan_mutex);
|
||||
|
||||
_timespan_thread->join ();
|
||||
|
||||
pthread_cond_destroy (&_timespan_cond);
|
||||
pthread_mutex_destroy (&_timespan_mutex);
|
||||
}
|
||||
|
||||
void*
|
||||
ExportHandler::_timespan_thread_run (void* me)
|
||||
{
|
||||
ExportHandler* self = static_cast<ExportHandler*> (me);
|
||||
|
||||
SessionEvent::create_per_thread_pool ("ExportHandler", 512);
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), "ExportHandler", 512);
|
||||
|
||||
pthread_mutex_lock (&self->_timespan_mutex);
|
||||
while (self->_timespan_thread_active.load ()) {
|
||||
pthread_cond_wait (&self->_timespan_cond, &self->_timespan_mutex);
|
||||
if (!self->_timespan_thread_active.load ()) {
|
||||
break;
|
||||
} else {
|
||||
Temporal::TempoMap::fetch ();
|
||||
self->process_connection.disconnect ();
|
||||
Glib::Threads::Mutex::Lock l (self->export_status->lock());
|
||||
DiskReader::allocate_working_buffers ();
|
||||
self->start_timespan ();
|
||||
DiskReader::free_working_buffers ();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&self->_timespan_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ExportHandler::timespan_thread_wakeup ()
|
||||
{
|
||||
if (pthread_mutex_trylock (&_timespan_mutex) == 0) {
|
||||
pthread_cond_signal (&_timespan_cond);
|
||||
pthread_mutex_unlock (&_timespan_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add an export to the `to-do' list */
|
||||
@ -372,22 +426,6 @@ ExportHandler::command_output(std::string output, size_t size)
|
||||
info << output << endmsg;
|
||||
}
|
||||
|
||||
void*
|
||||
ExportHandler::start_timespan_bg (void* eh)
|
||||
{
|
||||
char name[64];
|
||||
snprintf (name, 64, "Export-TS-%p", (void*)DEBUG_THREAD_SELF);
|
||||
pthread_set_name (name);
|
||||
ExportHandler* self = static_cast<ExportHandler*> (eh);
|
||||
self->process_connection.disconnect ();
|
||||
Glib::Threads::Mutex::Lock l (self->export_status->lock());
|
||||
SessionEvent::create_per_thread_pool (name, 512);
|
||||
DiskReader::allocate_working_buffers ();
|
||||
self->start_timespan ();
|
||||
DiskReader::free_working_buffers ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ExportHandler::finish_timespan ()
|
||||
{
|
||||
@ -543,9 +581,7 @@ ExportHandler::finish_timespan ()
|
||||
/* finish timespan is called in freewheeling rt-context,
|
||||
* we cannot start a new export from here */
|
||||
assert (AudioEngine::instance()->freewheeling ());
|
||||
pthread_t tid;
|
||||
pthread_create (&tid, NULL, ExportHandler::start_timespan_bg, this);
|
||||
pthread_detach (tid);
|
||||
timespan_thread_wakeup ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -815,7 +815,8 @@ ARDOUR::init_post_engine (uint32_t start_cnt)
|
||||
}
|
||||
}
|
||||
|
||||
BaseUI::set_thread_priority (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority () - 2));
|
||||
/* set/update thread priority relative to backend's [jack_]client_real_time_priority */
|
||||
BaseUI::set_thread_priority (PBD_RT_PRI_CTRL);
|
||||
|
||||
TransportMasterManager::instance ().restart ();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "ardour/disk_reader.h"
|
||||
#include "ardour/io_tasklist.h"
|
||||
#include "ardour/process_thread.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/session_event.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
@ -50,35 +51,41 @@ IOTaskList::IOTaskList (uint32_t n_threads)
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_attr_t attr;
|
||||
struct sched_param parm;
|
||||
parm.sched_priority = pbd_absolute_rt_priority (SCHED_RR, pbd_pthread_priority (THREAD_IO));
|
||||
bool use_rt;
|
||||
int policy;
|
||||
|
||||
switch (Config->get_io_thread_policy ()) {
|
||||
case 1:
|
||||
use_rt = true;
|
||||
policy = SCHED_FIFO;
|
||||
break;
|
||||
case 2:
|
||||
use_rt = true;
|
||||
policy = SCHED_RR;
|
||||
default:
|
||||
use_rt = false;
|
||||
policy = SCHED_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_attr_init (&attr);
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
pthread_attr_setschedpolicy (&attr, SCHED_OTHER);
|
||||
#else
|
||||
pthread_attr_setschedpolicy (&attr, SCHED_RR);
|
||||
policy = SCHED_OTHER;
|
||||
#endif
|
||||
pthread_attr_setschedparam (&attr, &parm);
|
||||
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::IOTaskList, string_compose ("IOTaskList starting %1 threads with priority = %2\n", _n_threads, parm.sched_priority));
|
||||
DEBUG_TRACE (PBD::DEBUG::IOTaskList, string_compose ("IOTaskList starting %1 threads with sched policy = %2\n", _n_threads, policy));
|
||||
|
||||
_workers.resize (_n_threads);
|
||||
for (uint32_t i = 0; i < _n_threads; ++i) {
|
||||
if (pthread_create (&_workers[i], &attr, &_worker_thread, this)) {
|
||||
if (pthread_create (&_workers[i], NULL, &_worker_thread, this)) {
|
||||
if (!use_rt || pbd_realtime_pthread_create (policy, THREAD_IO, 0, &_workers[i], &_worker_thread, this)) {
|
||||
if (use_rt && i == 0) {
|
||||
PBD::warning << _("IOTaskList: cannot acquire realtime permissions.") << endmsg;
|
||||
}
|
||||
if (pbd_pthread_create (0, &_workers[i], &_worker_thread, this)) {
|
||||
std::cerr << "Failed to start IOTaskList thread\n";
|
||||
throw failed_constructor ();
|
||||
}
|
||||
if (i == 0) {
|
||||
PBD::warning << _("IOTaskList: cannot acquire realtime permissions.") << endmsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy (&attr);
|
||||
}
|
||||
|
||||
IOTaskList::~IOTaskList ()
|
||||
@ -139,8 +146,8 @@ IOTaskList::_worker_thread (void* me)
|
||||
|
||||
#ifdef HAVE_IOPRIO
|
||||
/* compare to Butler::_thread_work */
|
||||
// ioprio_set (IOPRIO_WHO_PROCESS, 0 /*calling thread*/, IOPRIO_PRIO_VALUE (IOPRIO_CLASS_RT, 4))
|
||||
syscall (SYS_ioprio_set, 1, 0, (1 << 13) | 4);
|
||||
// ioprio_set (IOPRIO_WHO_PROCESS, 0 /*calling thread*/, IOPRIO_PRIO_VALUE (IOPRIO_CLASS_RT, 4))
|
||||
syscall (SYS_ioprio_set, 1, 0, (1 << 13) | 4);
|
||||
#endif
|
||||
|
||||
self->io_thread ();
|
||||
|
@ -607,7 +607,7 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
|
||||
static const int32_t _min_block_length = 1; // may happen during split-cycles
|
||||
static const int32_t _max_block_length = 8192; // max possible (with all engines and during export)
|
||||
static const int32_t rt_policy = PBD_SCHED_FIFO;
|
||||
static const int32_t rt_priority = pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority () - 1);
|
||||
static const int32_t rt_priority = pbd_absolute_rt_priority (PBD_SCHED_FIFO, PBD_RT_PRI_PROC);
|
||||
static const int32_t hw_concurrency = how_many_dsp_threads ();
|
||||
/* Consider updating max-block-size whenever the buffersize changes.
|
||||
* It requires re-instantiating the plugin (which is a non-realtime operation),
|
||||
|
@ -275,7 +275,6 @@ MidiPatchManager::load_midnams ()
|
||||
*/
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), "midi-patch-manager", 8);
|
||||
pthread_set_name ("MIDNAMLoader");
|
||||
|
||||
{
|
||||
PBD::Unwinder<bool> npc (no_patch_changed_messages, true);
|
||||
@ -291,7 +290,7 @@ MidiPatchManager::load_midnams ()
|
||||
void
|
||||
MidiPatchManager::load_midnams_in_thread ()
|
||||
{
|
||||
_midnam_load_thread = PBD::Thread::create (boost::bind (&MidiPatchManager::load_midnams, this));
|
||||
_midnam_load_thread = PBD::Thread::create (boost::bind (&MidiPatchManager::load_midnams, this), "MIDNAMLoader");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3413,17 +3413,14 @@ Playlist::fade_range (list<TimelineRange>& ranges)
|
||||
{
|
||||
ThawList thawlist;
|
||||
RegionReadLock rlock (this);
|
||||
for (list<TimelineRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
|
||||
list<TimelineRange>::iterator tmpr = r;
|
||||
++tmpr;
|
||||
for (RegionList::const_iterator i = regions.begin (); i != regions.end ();) {
|
||||
RegionList::const_iterator tmpi = i;
|
||||
++tmpi;
|
||||
thawlist.add (*i);
|
||||
(*i)->fade_range ((*r).start().samples(), (*r).end().samples());
|
||||
i = tmpi;
|
||||
/* add regions only once, not for each range */
|
||||
for (auto const& r : regions) {
|
||||
thawlist.add (r);
|
||||
}
|
||||
for (auto const& t: ranges) {
|
||||
for (auto const& r : regions) {
|
||||
r->fade_range (t.start().samples(), t.end().samples());
|
||||
}
|
||||
r = tmpr;
|
||||
}
|
||||
rlock.release ();
|
||||
thawlist.release ();
|
||||
|
@ -410,7 +410,7 @@ Route::process_output_buffers (BufferSet& bufs,
|
||||
_pannable->automation_run (start_sample, nframes);
|
||||
}
|
||||
|
||||
const int speed = (is_auditioner() ? 1 : _session.transport_speed ());
|
||||
const int speed = (is_auditioner() ? 1 : _session.transport_speed (true));
|
||||
assert (speed == -1 || speed == 0 || speed == 1);
|
||||
|
||||
const samplecnt_t output_latency = speed * _output_latency;
|
||||
@ -4050,7 +4050,7 @@ Route::latency_preroll (pframes_t nframes, samplepos_t& start_sample, samplepos_
|
||||
return nframes;
|
||||
}
|
||||
if (!_disk_reader) {
|
||||
if (_session.transport_speed() < 0) {
|
||||
if (_session.transport_speed (true) < 0) {
|
||||
start_sample += latency_preroll;
|
||||
end_sample += latency_preroll;
|
||||
} else {
|
||||
@ -4060,12 +4060,12 @@ Route::latency_preroll (pframes_t nframes, samplepos_t& start_sample, samplepos_
|
||||
return nframes;
|
||||
}
|
||||
|
||||
if (latency_preroll > playback_latency ()) {
|
||||
if (latency_preroll >= playback_latency ()) {
|
||||
no_roll_unlocked (nframes, start_sample - latency_preroll, end_sample - latency_preroll, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_session.transport_speed() < 0) {
|
||||
if (_session.transport_speed (true) < 0) {
|
||||
start_sample += latency_preroll;
|
||||
end_sample += latency_preroll;
|
||||
} else {
|
||||
@ -5927,8 +5927,15 @@ Route::send_pan_azimuth_controllable (uint32_t n) const
|
||||
}
|
||||
|
||||
std::shared_ptr<AutomationControl>
|
||||
Route::send_level_controllable (uint32_t n) const
|
||||
Route::send_level_controllable (uint32_t n, bool locked) const
|
||||
{
|
||||
if (locked) {
|
||||
/* calling thread has a WriterLock (_processor_lock)
|
||||
* we cannot call nth_send()
|
||||
*/
|
||||
return std::shared_ptr<AutomationControl>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Send> s = std::dynamic_pointer_cast<Send>(nth_send (n));
|
||||
if (s) {
|
||||
return s->gain_control ();
|
||||
|
@ -7845,8 +7845,10 @@ Session::auto_connect_thread_start ()
|
||||
lx.release ();
|
||||
|
||||
_ac_thread_active.store (1);
|
||||
if (pthread_create (&_auto_connect_thread, NULL, auto_connect_thread, this)) {
|
||||
if (pthread_create_and_store ("AutoConnect", &_auto_connect_thread, auto_connect_thread, this, 0)) {
|
||||
_ac_thread_active.store (0);
|
||||
fatal << "Cannot create 'session auto connect' thread" << endmsg;
|
||||
abort(); /* NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -7881,9 +7883,7 @@ void *
|
||||
Session::auto_connect_thread (void *arg)
|
||||
{
|
||||
Session *s = static_cast<Session *>(arg);
|
||||
pthread_set_name (X_("autoconnect"));
|
||||
s->auto_connect_thread_run ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,9 @@ Session::calc_preroll_subcycle (samplecnt_t ns) const
|
||||
{
|
||||
std::shared_ptr<RouteList const> r = routes.reader ();
|
||||
for (auto const& i : *r) {
|
||||
if (!i->active ()) {
|
||||
continue;
|
||||
}
|
||||
samplecnt_t route_offset = i->playback_latency ();
|
||||
if (_remaining_latency_preroll > route_offset + ns) {
|
||||
/* route will no-roll for complete pre-roll cycle */
|
||||
@ -1199,7 +1202,7 @@ Session::emit_thread_start ()
|
||||
}
|
||||
_rt_thread_active = true;
|
||||
|
||||
if (pthread_create (&_rt_emit_thread, NULL, emit_thread, this)) {
|
||||
if (pthread_create_and_store ("SessionSignals", &_rt_emit_thread, emit_thread, this, 0)) {
|
||||
_rt_thread_active = false;
|
||||
}
|
||||
}
|
||||
@ -1225,9 +1228,7 @@ void *
|
||||
Session::emit_thread (void *arg)
|
||||
{
|
||||
Session *s = static_cast<Session *>(arg);
|
||||
pthread_set_name ("SessionSignals");
|
||||
s->emit_thread_run ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2142,11 +2142,14 @@ Session::transport_will_roll_forwards () const
|
||||
}
|
||||
|
||||
double
|
||||
Session::transport_speed() const
|
||||
Session::transport_speed (bool incl_preroll) const
|
||||
{
|
||||
if (_transport_fsm->transport_speed() != _transport_fsm->transport_speed()) {
|
||||
// cerr << "\n\n!!TS " << _transport_fsm->transport_speed() << " TFSM::speed " << _transport_fsm->transport_speed() << " via " << _transport_fsm->current_state() << endl;
|
||||
}
|
||||
if (incl_preroll) {
|
||||
return _transport_fsm->transport_speed();
|
||||
}
|
||||
return _count_in_samples > 0 ? 0. : _transport_fsm->transport_speed();
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,6 @@ static void
|
||||
peak_thread_work ()
|
||||
{
|
||||
SessionEvent::create_per_thread_pool (X_("PeakFile Builder "), 64);
|
||||
pthread_set_name ("PeakFileBuilder");
|
||||
|
||||
while (true) {
|
||||
SourceFactory::peak_building_lock.lock ();
|
||||
|
||||
@ -119,7 +117,7 @@ SourceFactory::init ()
|
||||
}
|
||||
peak_thread_run = true;
|
||||
for (int n = 0; n < 2; ++n) {
|
||||
peak_thread_pool.push_back (PBD::Thread::create (&peak_thread_work));
|
||||
peak_thread_pool.push_back (PBD::Thread::create (&peak_thread_work, string_compose ("PeakFileBuilder-%1", n)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4879,7 +4879,7 @@ TriggerBoxThread::TriggerBoxThread ()
|
||||
: requests (1024)
|
||||
, _xthread (true)
|
||||
{
|
||||
if (pthread_create_and_store ("triggerbox thread", &thread, _thread_work, this)) {
|
||||
if (pthread_create_and_store ("TriggerBox Worker", &thread, _thread_work, this)) {
|
||||
error << _("Session: could not create triggerbox thread") << endmsg;
|
||||
throw failed_constructor ();
|
||||
}
|
||||
@ -4897,15 +4897,12 @@ void *
|
||||
TriggerBoxThread::_thread_work (void* arg)
|
||||
{
|
||||
SessionEvent::create_per_thread_pool ("tbthread events", 4096);
|
||||
pthread_set_name (X_("tbthread"));
|
||||
return ((TriggerBoxThread *) arg)->thread_work ();
|
||||
}
|
||||
|
||||
void *
|
||||
TriggerBoxThread::thread_work ()
|
||||
{
|
||||
pthread_set_name (X_("Trigger Worker"));
|
||||
|
||||
while (true) {
|
||||
|
||||
char msg;
|
||||
|
@ -1195,6 +1195,7 @@ VST3PI::VST3PI (std::shared_ptr<ARDOUR::VST3PluginModule> m, std::string unique_
|
||||
, _rpc_queue (RouteProcessorChange::NoProcessorChange, false)
|
||||
, _no_kMono (false)
|
||||
, _restart_component_is_synced (false)
|
||||
, _in_set_owner (false)
|
||||
{
|
||||
using namespace std;
|
||||
IPluginFactory* factory = m->factory ();
|
||||
@ -1835,9 +1836,13 @@ VST3PI::set_owner (SessionObject* o)
|
||||
return;
|
||||
}
|
||||
|
||||
_in_set_owner.store (true);
|
||||
|
||||
if (!setup_psl_info_handler ()) {
|
||||
setup_info_listener ();
|
||||
}
|
||||
|
||||
_in_set_owner.store (false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2809,7 +2814,7 @@ VST3PI::automation_state_changed (uint32_t port, AutoState s, std::weak_ptr<Auto
|
||||
/* ****************************************************************************/
|
||||
|
||||
static std::shared_ptr<AutomationControl>
|
||||
lookup_ac (SessionObject* o, FIDString id)
|
||||
lookup_ac (SessionObject* o, FIDString id, bool locked = false)
|
||||
{
|
||||
Stripable* s = dynamic_cast<Stripable*> (o);
|
||||
if (!s) {
|
||||
@ -2842,8 +2847,8 @@ lookup_ac (SessionObject* o, FIDString id)
|
||||
* recurive locks (deadlock, or double unlock crash).
|
||||
*/
|
||||
int send_id = atoi (id + strlen (ContextInfo::kSendLevel));
|
||||
if (s->send_enable_controllable (send_id)) {
|
||||
return s->send_level_controllable (send_id);
|
||||
if (send_id >=0 && s->send_enable_controllable (send_id)) {
|
||||
return s->send_level_controllable (send_id, locked);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -2964,12 +2969,13 @@ VST3PI::getContextInfoValue (double& value, FIDString id)
|
||||
if (0 == strcmp (id, ContextInfo::kMaxVolume)) {
|
||||
value = s->gain_control ()->upper ();
|
||||
} else if (0 == strcmp (id, ContextInfo::kMaxSendLevel)) {
|
||||
value = 2.0; // Config->get_max_gain();
|
||||
#ifdef MIXBUS
|
||||
if (s->send_level_controllable (0)) {
|
||||
if (s->send_enable_controllable (0)) {
|
||||
assert (s->send_level_controllable (0));
|
||||
value = s->send_level_controllable (0)->upper (); // pow (10.0, .05 * 15.0);
|
||||
}
|
||||
#endif
|
||||
value = 2.0; // Config->get_max_gain();
|
||||
} else if (0 == strcmp (id, ContextInfo::kVolume)) {
|
||||
std::shared_ptr<AutomationControl> ac = s->gain_control ();
|
||||
value = ac->get_value (); // gain coefficient 0..2 (1.0 = 0dB)
|
||||
@ -2983,11 +2989,12 @@ VST3PI::getContextInfoValue (double& value, FIDString id)
|
||||
value = 0.5; // center
|
||||
}
|
||||
} else if (0 == strncmp (id, ContextInfo::kSendLevel, strlen (ContextInfo::kSendLevel))) {
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id, _in_set_owner.load ());
|
||||
if (ac) {
|
||||
value = ac->get_value (); // gain cofficient
|
||||
psl_subscribe_to (ac, id);
|
||||
} else {
|
||||
value = 0;
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::getContextInfoValue<double> invalid AC %1\n", id));
|
||||
return kInvalidArgument; // send index out of bounds
|
||||
}
|
||||
@ -3023,14 +3030,14 @@ VST3PI::setContextInfoValue (FIDString id, double value)
|
||||
ac->set_value (ac->interface_to_internal (value, true), PBD::Controllable::NoGroup);
|
||||
}
|
||||
} else if (0 == strncmp (id, ContextInfo::kSendLevel, strlen (ContextInfo::kSendLevel))) {
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id, _in_set_owner.load ());
|
||||
if (ac) {
|
||||
ac->set_value (value, Controllable::NoGroup);
|
||||
} else {
|
||||
return kInvalidArgument; // send index out of bounds
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, "VST3PI::setContextInfoValue<double>: unsupported ID\n");
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::setContextInfoValue<double>: unsupported ID %1\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
return kResultOk;
|
||||
@ -3071,7 +3078,7 @@ VST3PI::setContextInfoValue (FIDString id, int32 value)
|
||||
s->session ().set_control (ac, value != 0 ? 1 : 0, Controllable::NoGroup);
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, "VST3PI::setContextInfoValue<int>: unsupported ID\n");
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::setContextInfoValue<int>: unsupported ID %1\n", id));
|
||||
return kNotImplemented;
|
||||
}
|
||||
return kResultOk;
|
||||
@ -3101,6 +3108,7 @@ VST3PI::beginEditContextInfoValue (FIDString id)
|
||||
}
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
if (!ac) {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::beginEditContextInfoValue %1 -- invalid AC\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::beginEditContextInfoValue %1\n", id));
|
||||
@ -3117,6 +3125,7 @@ VST3PI::endEditContextInfoValue (FIDString id)
|
||||
}
|
||||
std::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
|
||||
if (!ac) {
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::endEditContextInfoValue %1 -- invalid AC\n", id));
|
||||
return kInvalidArgument;
|
||||
}
|
||||
DEBUG_TRACE (DEBUG::VST3Callbacks, string_compose ("VST3PI::endEditContextInfoValue %1\n", id));
|
||||
|
@ -41,7 +41,7 @@ Worker::Worker(Workee* workee, uint32_t ring_size, bool threaded)
|
||||
, _synchronous(!threaded)
|
||||
{
|
||||
if (threaded) {
|
||||
_thread = PBD::Thread::create (boost::bind (&Worker::run, this));
|
||||
_thread = PBD::Thread::create (boost::bind (&Worker::run, this), "LV2Worker");
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,8 +137,6 @@ Worker::emit_responses()
|
||||
void
|
||||
Worker::run()
|
||||
{
|
||||
pthread_set_name ("LV2Worker");
|
||||
|
||||
void* buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
while (true) {
|
||||
|
@ -136,9 +136,7 @@ class TmpFileRt
|
||||
static void * _disk_thread (void *arg)
|
||||
{
|
||||
TmpFileRt *d = static_cast<TmpFileRt *>(arg);
|
||||
pthread_set_name ("ExportDiskIO");
|
||||
d->disk_thread ();
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -158,7 +156,7 @@ class TmpFileRt
|
||||
pthread_mutex_init (&_disk_thread_lock, 0);
|
||||
pthread_cond_init (&_data_ready, 0);
|
||||
|
||||
if (pthread_create (&_thread_id, NULL, _disk_thread, this)) {
|
||||
if (pthread_create_and_store ("ExportDiskIO", &_thread_id, _disk_thread, this, 0)) {
|
||||
_capture = false;
|
||||
if (SndfileWriter<T>::throw_level (ThrowStrict)) {
|
||||
throw Exception (*this, "Cannot create export disk writer");
|
||||
|
@ -1385,7 +1385,7 @@ AlsaAudioBackend::midi_device_thread ()
|
||||
bool
|
||||
AlsaAudioBackend::listen_for_midi_device_changes ()
|
||||
{
|
||||
if (pthread_create (&_midi_device_thread_id, NULL, _midi_device_thread, this)) {
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_HELP, &_midi_device_thread_id, _midi_device_thread, this)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -605,7 +605,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||
return PortReconnectError;
|
||||
}
|
||||
|
||||
if (pthread_create (&_freeewheel_thread, NULL, pthread_freewheel, this))
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_freeewheel_thread, pthread_freewheel, this))
|
||||
{
|
||||
PBD::error << _("CoreAudioBackend: failed to create process thread.") << endmsg;
|
||||
delete _pcmio; _pcmio = 0;
|
||||
|
@ -856,7 +856,7 @@ static void* freewheel_thread(void* arg)
|
||||
bool
|
||||
PortAudioBackend::start_freewheel_process_thread ()
|
||||
{
|
||||
if (pthread_create(&_pthread_freewheel, NULL, freewheel_thread, this)) {
|
||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_pthread_freewheel, freewheel_thread, this)) {
|
||||
DEBUG_AUDIO("Failed to create main audio thread\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ using namespace PBD;
|
||||
using namespace Glib;
|
||||
|
||||
uint64_t BaseUI::rt_bit = 1;
|
||||
int BaseUI::_thread_priority = PBD_RT_PRI_PROC - 1;
|
||||
int BaseUI::_thread_priority = PBD_RT_PRI_CTRL;
|
||||
|
||||
BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
|
||||
BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type();
|
||||
@ -94,7 +94,6 @@ BaseUI::set_thread_priority () const
|
||||
void
|
||||
BaseUI::main_thread ()
|
||||
{
|
||||
pthread_set_name (string_compose ("UI:%1", event_loop_name ()).c_str ());
|
||||
DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", event_loop_name(), pthread_name()));
|
||||
set_event_loop_for_thread (this);
|
||||
thread_init ();
|
||||
@ -122,7 +121,7 @@ BaseUI::run ()
|
||||
attach_request_source ();
|
||||
|
||||
Glib::Threads::Mutex::Lock lm (_run_lock);
|
||||
_run_loop_thread = PBD::Thread::create (boost::bind (&BaseUI::main_thread, this));
|
||||
_run_loop_thread = PBD::Thread::create (boost::bind (&BaseUI::main_thread, this), string_compose ("UI:%1", event_loop_name ()));
|
||||
_running.wait (_run_lock);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ DebugBits PBD::DEBUG::Configuration = PBD::new_debug_bit ("configuration");
|
||||
DebugBits PBD::DEBUG::UndoHistory = PBD::new_debug_bit ("undohistory");
|
||||
DebugBits PBD::DEBUG::Timing = PBD::new_debug_bit ("timing");
|
||||
DebugBits PBD::DEBUG::Threads = PBD::new_debug_bit ("threads");
|
||||
DebugBits PBD::DEBUG::ThreadName = PBD::new_debug_bit ("threadname");
|
||||
DebugBits PBD::DEBUG::Locale = PBD::new_debug_bit ("locale");
|
||||
DebugBits PBD::DEBUG::StringConvert = PBD::new_debug_bit ("stringconvert");
|
||||
DebugBits PBD::DEBUG::DebugTimestamps = PBD::new_debug_bit ("debugtimestamps");
|
||||
@ -103,7 +104,7 @@ PBD::new_debug_bit (const char* name)
|
||||
void
|
||||
PBD::debug_only_print (const char* prefix, string str)
|
||||
{
|
||||
if ((PBD::debug_bits & DEBUG::Threads).any()) {
|
||||
if ((PBD::debug_bits & DEBUG::ThreadName).any()) {
|
||||
printf ("0x%lx (%s) ", (intptr_t) DEBUG_THREAD_SELF, pthread_name());
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ Downloader::start ()
|
||||
|
||||
_cancel = false;
|
||||
_status = 0; /* unknown at this point */
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Downloader::download, this)));
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Downloader::download, this), "Downloader"));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -59,7 +59,6 @@ write_callback (void* buffer, size_t size, size_t nmemb, void* d)
|
||||
static void*
|
||||
get_url (void* arg)
|
||||
{
|
||||
pthread_set_name ("FileArchiveURL");
|
||||
FileArchive::Request* r = (FileArchive::Request*) arg;
|
||||
CURL* curl;
|
||||
|
||||
@ -328,7 +327,10 @@ std::vector<std::string>
|
||||
FileArchive::contents_url ()
|
||||
{
|
||||
_req.mp.reset ();
|
||||
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
||||
|
||||
if (pthread_create_and_store ("FileArchiveHTTP", &_tid, get_url, (void*)&_req, 0)) {
|
||||
return std::vector<std::string> ();
|
||||
}
|
||||
|
||||
struct archive* a = setup_archive ();
|
||||
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
||||
@ -359,7 +361,9 @@ int
|
||||
FileArchive::extract_url ()
|
||||
{
|
||||
_req.mp.reset ();
|
||||
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
||||
if (pthread_create_and_store ("FileArchiveHTTP", &_tid, get_url, (void*)&_req)) {
|
||||
return -1;
|
||||
}
|
||||
struct archive* a = setup_archive ();
|
||||
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
||||
int rv = do_extract (a);
|
||||
|
@ -45,7 +45,7 @@ Inflater::~Inflater ()
|
||||
int
|
||||
Inflater::start ()
|
||||
{
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Inflater::threaded_inflate, this)));
|
||||
return 0 != (thread = PBD::Thread::create (boost::bind (&Inflater::threaded_inflate, this), "Inflater"));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
namespace PBD {
|
||||
|
||||
typedef std::bitset<128> DebugBits;
|
||||
typedef std::bitset<192> DebugBits;
|
||||
|
||||
LIBPBD_API extern DebugBits debug_bits;
|
||||
LIBPBD_API DebugBits new_debug_bit (const char* name);
|
||||
@ -64,6 +64,7 @@ namespace PBD {
|
||||
LIBPBD_API extern DebugBits UndoHistory;
|
||||
LIBPBD_API extern DebugBits Timing;
|
||||
LIBPBD_API extern DebugBits Threads;
|
||||
LIBPBD_API extern DebugBits ThreadName;
|
||||
LIBPBD_API extern DebugBits Locale;
|
||||
LIBPBD_API extern DebugBits StringConvert;
|
||||
LIBPBD_API extern DebugBits DebugTimestamps;
|
||||
|
@ -57,6 +57,7 @@
|
||||
# define PBD_RT_PRI_MAIN pbd_pthread_priority (THREAD_MAIN)
|
||||
# define PBD_RT_PRI_MIDI pbd_pthread_priority (THREAD_MIDI)
|
||||
# define PBD_RT_PRI_PROC pbd_pthread_priority (THREAD_PROC)
|
||||
# define PBD_RT_PRI_CTRL pbd_pthread_priority (THREAD_CTRL)
|
||||
|
||||
LIBPBD_API int pthread_create_and_store (std::string name, pthread_t *thread, void * (*start_routine)(void *), void * arg, uint32_t stacklimit = 0x80000 /*512kB*/);
|
||||
LIBPBD_API void pthread_cancel_one (pthread_t thread);
|
||||
@ -65,10 +66,13 @@ LIBPBD_API void pthread_kill_all (int signum);
|
||||
LIBPBD_API const char* pthread_name ();
|
||||
LIBPBD_API void pthread_set_name (const char* name);
|
||||
|
||||
LIBPBD_API void pbd_set_engine_rt_priority (int);
|
||||
|
||||
enum PBDThreadClass {
|
||||
THREAD_MAIN, // main audio I/O thread
|
||||
THREAD_MIDI, // MIDI I/O threads
|
||||
THREAD_PROC, // realtime worker
|
||||
THREAD_CTRL, // Automation watch, BaseUI
|
||||
THREAD_IO // non-realtime I/O
|
||||
};
|
||||
|
||||
@ -88,7 +92,7 @@ LIBPBD_API int pbd_realtime_pthread_create (
|
||||
void *arg);
|
||||
|
||||
LIBPBD_API int pbd_absolute_rt_priority (int policy, int priority);
|
||||
LIBPBD_API int pbd_set_thread_priority (pthread_t, const int policy, int priority);
|
||||
LIBPBD_API int pbd_set_thread_priority (pthread_t, int policy, int priority);
|
||||
LIBPBD_API bool pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns, bool main);
|
||||
|
||||
namespace PBD {
|
||||
@ -97,7 +101,7 @@ namespace PBD {
|
||||
|
||||
class LIBPBD_API Thread {
|
||||
public:
|
||||
static Thread* create (boost::function<void ()> const&, std::string const& name = "");
|
||||
static Thread* create (boost::function<void ()> const&, std::string const& name);
|
||||
static Thread* self ();
|
||||
void join ();
|
||||
bool caller_is_self () const;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2015 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2007-2009 David Robillard <d@drobilla.net>
|
||||
* Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2015-2024 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* 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
|
||||
@ -23,11 +23,17 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined PLATFORM_WINDOWS && defined __GLIBC__
|
||||
#include <climits>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/debug.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
@ -37,6 +43,8 @@ DECLARE_DEFAULT_COMPARISONS (pthread_t) // Needed for 'DECLARE_DEFAULT_COMPARISO
|
||||
// if the type of object being contained has no appropriate comparison operators
|
||||
// defined (specifically, if operators '<' and '==' are undefined). This seems
|
||||
// to be the case with ptw32 'pthread_t' which is a simple struct.
|
||||
|
||||
#define pthread_gethandle pthread_getw32threadhandle_np
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -47,10 +55,54 @@ DECLARE_DEFAULT_COMPARISONS (pthread_t) // Needed for 'DECLARE_DEFAULT_COMPARISO
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef std::list<pthread_t> ThreadMap;
|
||||
static ThreadMap all_threads;
|
||||
static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static Glib::Threads::Private<char> thread_name (free);
|
||||
typedef std::map<pthread_t, std::string> ThreadMap;
|
||||
static ThreadMap all_threads;
|
||||
static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static Glib::Threads::Private<char> thread_name (free);
|
||||
static int base_priority_relative_to_max = -20;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
static
|
||||
std::string GetLastErrorAsString()
|
||||
{
|
||||
DWORD err = ::GetLastError();
|
||||
if(err == 0) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
LPSTR buf = nullptr;
|
||||
size_t size = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
|
||||
|
||||
std::string rv (buf, size);
|
||||
LocalFree (buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_win_set_realtime_policy (pthread_t thread, int priority)
|
||||
{
|
||||
if (priority < 12) {
|
||||
return false;
|
||||
}
|
||||
bool ok = false;
|
||||
|
||||
if (SetPriorityClass (GetCurrentProcess (), 0x00000100 /* REALTIME_PRIORITY_CLASS */)) {
|
||||
/* see https://learn.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities */
|
||||
ok = SetThreadPriority (pthread_gethandle (thread), priority);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Using Windows RT thread class. set priority: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
} else {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Cannot use Windows RT thread class: %1\n", GetLastErrorAsString ()));
|
||||
ok = SetPriorityClass (GetCurrentProcess (), 0x00000080 /* HIGH_PRIORITY_CLASS */);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Using Windows high priority thread class: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
if (ok) {
|
||||
ok = SetThreadPriority (pthread_gethandle (thread), priority);
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Set Windows high thread priority: %1\n", ok ? "OK" : GetLastErrorAsString ()));
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace PBD
|
||||
{
|
||||
@ -72,148 +124,6 @@ PBD::notify_event_loops_about_thread_creation (pthread_t thread, const std::stri
|
||||
ThreadCreatedWithRequestSize (thread, emitting_thread_name, request_count);
|
||||
}
|
||||
|
||||
struct ThreadStartWithName {
|
||||
void* (*thread_work) (void*);
|
||||
void* arg;
|
||||
std::string name;
|
||||
|
||||
ThreadStartWithName (void* (*f) (void*), void* a, const std::string& s)
|
||||
: thread_work (f)
|
||||
, arg (a)
|
||||
, name (s)
|
||||
{}
|
||||
};
|
||||
|
||||
static void*
|
||||
fake_thread_start (void* arg)
|
||||
{
|
||||
ThreadStartWithName* ts = (ThreadStartWithName*)arg;
|
||||
void* (*thread_work) (void*) = ts->thread_work;
|
||||
void* thread_arg = ts->arg;
|
||||
|
||||
/* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
|
||||
pthread_set_name (ts->name.c_str ());
|
||||
|
||||
/* we don't need this object anymore */
|
||||
delete ts;
|
||||
|
||||
/* actually run the thread's work function */
|
||||
void* ret = thread_work (thread_arg);
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (pthread_equal ((*i), pthread_self ())) {
|
||||
all_threads.erase (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
/* done */
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_create_and_store (string name, pthread_t* thread, void* (*start_routine) (void*), void* arg, uint32_t stacklimit)
|
||||
{
|
||||
pthread_attr_t default_attr;
|
||||
int ret;
|
||||
|
||||
/* set default stack size to sensible default for memlocking */
|
||||
pthread_attr_init (&default_attr);
|
||||
if (stacklimit > 0) {
|
||||
pthread_attr_setstacksize (&default_attr, stacklimit);
|
||||
}
|
||||
|
||||
ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
|
||||
|
||||
if ((ret = pthread_create (thread, &default_attr, fake_thread_start, ts)) == 0) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads.push_back (*thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
pthread_attr_destroy (&default_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
pthread_set_name (const char* str)
|
||||
{
|
||||
/* copy string and delete it when exiting */
|
||||
thread_name.set (strdup (str)); // leaks
|
||||
|
||||
#if !defined PTW32_VERSION && defined _GNU_SOURCE
|
||||
/* set public thread name, up to 16 chars */
|
||||
char ptn[16];
|
||||
memset (ptn, 0, 16);
|
||||
strncpy (ptn, str, 15);
|
||||
pthread_setname_np (pthread_self (), ptn);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char*
|
||||
pthread_name ()
|
||||
{
|
||||
const char* str = thread_name.get ();
|
||||
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void
|
||||
pthread_kill_all (int signum)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (!pthread_equal ((*i), pthread_self ())) {
|
||||
pthread_kill ((*i), signum);
|
||||
}
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_all ()
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end ();) {
|
||||
ThreadMap::iterator nxt = i;
|
||||
++nxt;
|
||||
|
||||
if (!pthread_equal ((*i), pthread_self ())) {
|
||||
pthread_cancel ((*i));
|
||||
}
|
||||
|
||||
i = nxt;
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_one (pthread_t thread)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (ThreadMap::iterator i = all_threads.begin (); i != all_threads.end (); ++i) {
|
||||
if (pthread_equal ((*i), thread)) {
|
||||
all_threads.erase (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cancel (thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
static size_t
|
||||
pbd_stack_size ()
|
||||
{
|
||||
@ -250,6 +160,148 @@ pbd_stack_size ()
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct ThreadStartWithName {
|
||||
void* (*thread_work) (void*);
|
||||
void* arg;
|
||||
std::string name;
|
||||
|
||||
ThreadStartWithName (void* (*f) (void*), void* a, const std::string& s)
|
||||
: thread_work (f)
|
||||
, arg (a)
|
||||
, name (s)
|
||||
{}
|
||||
};
|
||||
|
||||
static void*
|
||||
fake_thread_start (void* arg)
|
||||
{
|
||||
ThreadStartWithName* ts = (ThreadStartWithName*)arg;
|
||||
void* (*thread_work) (void*) = ts->thread_work;
|
||||
void* thread_arg = ts->arg;
|
||||
|
||||
/* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
|
||||
pthread_set_name (ts->name.c_str ());
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Started: '%1'\n", ts->name));
|
||||
|
||||
/* we don't need this object anymore */
|
||||
delete ts;
|
||||
|
||||
/* actually run the thread's work function */
|
||||
void* ret = thread_work (thread_arg);
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Terminated: '%1'\n", t.second));
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
/* done */
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_create_and_store (string name, pthread_t* thread, void* (*start_routine) (void*), void* arg, uint32_t stacklimit)
|
||||
{
|
||||
pthread_attr_t default_attr;
|
||||
int ret;
|
||||
|
||||
/* set default stack size to sensible default for memlocking */
|
||||
pthread_attr_init (&default_attr);
|
||||
if (stacklimit > 0) {
|
||||
pthread_attr_setstacksize (&default_attr, stacklimit + pbd_stack_size ());
|
||||
}
|
||||
|
||||
ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
|
||||
|
||||
if ((ret = pthread_create (thread, &default_attr, fake_thread_start, ts)) == 0) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads[*thread] = name;
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
pthread_attr_destroy (&default_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
pthread_set_name (const char* str)
|
||||
{
|
||||
/* copy string and delete it when exiting */
|
||||
thread_name.set (strdup (str)); // leaks
|
||||
|
||||
#if !defined PTW32_VERSION && defined _GNU_SOURCE
|
||||
/* set public thread name, up to 16 chars */
|
||||
char ptn[16];
|
||||
memset (ptn, 0, 16);
|
||||
strncpy (ptn, str, 15);
|
||||
pthread_setname_np (pthread_self (), ptn);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char*
|
||||
pthread_name ()
|
||||
{
|
||||
const char* str = thread_name.get ();
|
||||
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void
|
||||
pthread_kill_all (int signum)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
continue;
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Kill: '%1'\n", t.second));
|
||||
pthread_kill (t.first, signum);
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_all ()
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
continue;
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Cancel: '%1'\n", t.second));
|
||||
pthread_cancel (t.first);
|
||||
}
|
||||
all_threads.clear ();
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
void
|
||||
pthread_cancel_one (pthread_t thread)
|
||||
{
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, thread)) {
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cancel (thread);
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
|
||||
int
|
||||
pbd_pthread_create (
|
||||
const size_t stacksize,
|
||||
@ -261,12 +313,28 @@ pbd_pthread_create (
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init (&attr);
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
if (stacksize > 0) {
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Start Non-RT Thread stacksize = 0x%1%2\n", std::hex, stacksize));
|
||||
rv = pthread_create (thread, &attr, start_routine, arg);
|
||||
pthread_attr_destroy (&attr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
pbd_set_engine_rt_priority (int p)
|
||||
{
|
||||
/* this is mainly for JACK's benefit */
|
||||
const int p_max = sched_get_priority_max (SCHED_FIFO);
|
||||
const int p_min = sched_get_priority_min (SCHED_FIFO);
|
||||
if (p <= 0 || p <= p_min + 10 || p > p_max) {
|
||||
base_priority_relative_to_max = -20;
|
||||
} else {
|
||||
base_priority_relative_to_max = p - p_max;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pbd_pthread_priority (PBDThreadClass which)
|
||||
{
|
||||
@ -274,24 +342,22 @@ pbd_pthread_priority (PBDThreadClass which)
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
switch (which) {
|
||||
case THREAD_MAIN:
|
||||
return -1;
|
||||
return -1; // THREAD_PRIORITY_TIME_CRITICAL (15)
|
||||
case THREAD_MIDI:
|
||||
return -2;
|
||||
default:
|
||||
case THREAD_PROC:
|
||||
return -2;
|
||||
case THREAD_CTRL:
|
||||
default:
|
||||
return -14; // THREAD_PRIORITY_HIGHEST (2)
|
||||
case THREAD_IO:
|
||||
/* https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/sched.c
|
||||
* -> THREAD_PRIORITY_HIGHEST
|
||||
*/
|
||||
return -13;
|
||||
/* https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/sched.c */
|
||||
return -15; // THREAD_PRIORITY_ABOVE_NORMAL (1)
|
||||
}
|
||||
#else
|
||||
int base = -20;
|
||||
int base = base_priority_relative_to_max;
|
||||
const char* p = getenv ("ARDOUR_SCHED_PRI");
|
||||
if (p && *p) {
|
||||
base = atoi (p);
|
||||
if (base > -5 && base < 5) {
|
||||
if (base > -5 || base < -85) {
|
||||
base = -20;
|
||||
}
|
||||
}
|
||||
@ -304,6 +370,8 @@ pbd_pthread_priority (PBDThreadClass which)
|
||||
default:
|
||||
case THREAD_PROC:
|
||||
return base - 2;
|
||||
case THREAD_CTRL:
|
||||
return base - 3;
|
||||
case THREAD_IO:
|
||||
return base - 10;
|
||||
}
|
||||
@ -314,26 +382,15 @@ int
|
||||
pbd_absolute_rt_priority (int policy, int priority)
|
||||
{
|
||||
/* POSIX requires a spread of at least 32 steps between min..max */
|
||||
const int p_min = sched_get_priority_min (policy); // Linux: 1
|
||||
const int p_max = sched_get_priority_max (policy); // Linux: 99
|
||||
const int p_min = sched_get_priority_min (policy); // Linux: 1 Windows -15
|
||||
const int p_max = sched_get_priority_max (policy); // Linux: 99 Windows +15
|
||||
|
||||
if (priority == 0) {
|
||||
assert (0);
|
||||
priority = (p_min + p_max) / 2;
|
||||
} else if (priority > 0) {
|
||||
/* value relative to minium */
|
||||
priority += p_min - 1;
|
||||
} else {
|
||||
/* value relative maximum */
|
||||
priority += p_max + 1;
|
||||
}
|
||||
/* priority is relative to the max */
|
||||
assert (priority < 0);
|
||||
priority += p_max + 1;
|
||||
|
||||
if (priority > p_max) {
|
||||
priority = p_max;
|
||||
}
|
||||
if (priority < p_min) {
|
||||
priority = p_min;
|
||||
}
|
||||
priority = std::min (p_max, priority);
|
||||
priority = std::max (p_min, priority);
|
||||
return priority;
|
||||
}
|
||||
|
||||
@ -356,19 +413,42 @@ pbd_realtime_pthread_create (
|
||||
pthread_attr_setschedparam (&attr, &parm);
|
||||
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
if (stacksize > 0) {
|
||||
pthread_attr_setstacksize (&attr, stacksize + pbd_stack_size ());
|
||||
}
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Start Realtime Thread policy = %1 priority = %2 stacksize = 0x%3%4\n", policy, parm.sched_priority, std::hex, stacksize));
|
||||
rv = pthread_create (thread, &attr, start_routine, arg);
|
||||
pthread_attr_destroy (&attr);
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (0 == rv && thread && parm.sched_priority >= 12) {
|
||||
set_win_set_realtime_policy (*thread, parm.sched_priority);
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
pbd_set_thread_priority (pthread_t thread, const int policy, int priority)
|
||||
pbd_set_thread_priority (pthread_t thread, int policy, int priority)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
policy = SCHED_OTHER;
|
||||
#endif
|
||||
|
||||
struct sched_param param;
|
||||
memset (¶m, 0, sizeof (param));
|
||||
param.sched_priority = pbd_absolute_rt_priority (policy, priority);
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Change '%1' to policy = %2 priority = %3\n", pthread_name(), policy, param.sched_priority));
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (is_pthread_active (thread) && param.sched_priority >= 12) {
|
||||
if (set_win_set_realtime_policy (thread, param.sched_priority)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return pthread_setschedparam (thread, SCHED_FIFO, ¶m);
|
||||
}
|
||||
|
||||
@ -484,6 +564,12 @@ PBD::Thread::Thread (boost::function<void ()> const& slot, std::string const& na
|
||||
if (pthread_create (&_t, &thread_attributes, _run, this)) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
if (_joinable) {
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
all_threads[_t] = name;
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
@ -492,8 +578,22 @@ PBD::Thread::_run (void* arg) {
|
||||
if (!self->_name.empty ()) {
|
||||
pthread_set_name (self->_name.c_str ());
|
||||
}
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Started: '%1'\n", self->_name));
|
||||
|
||||
self->_slot ();
|
||||
|
||||
/* cleanup */
|
||||
pthread_mutex_lock (&thread_map_lock);
|
||||
for (auto const& t : all_threads) {
|
||||
if (pthread_equal (t.first, pthread_self ())) {
|
||||
DEBUG_TRACE (PBD::DEBUG::Threads, string_compose ("Terminated: '%1'\n", t.second));
|
||||
all_threads.erase (t.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&thread_map_lock);
|
||||
|
||||
pthread_exit (0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -278,9 +278,7 @@ SystemExec::~SystemExec ()
|
||||
static void*
|
||||
interposer_thread (void *arg) {
|
||||
SystemExec *sex = static_cast<SystemExec *>(arg);
|
||||
pthread_set_name ("ExecStdOut");
|
||||
sex->output_interposer();
|
||||
pthread_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -522,7 +520,7 @@ SystemExec::start (StdErrMode stderr_mode, const char * /*vfork_exec_wrapper*/)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rv = pthread_create (&thread_id_tt, NULL, interposer_thread, this);
|
||||
int rv = pthread_create_and_store ("ExecStdOut", &thread_id_tt, interposer_thread, this, 0);
|
||||
thread_active=true;
|
||||
if (rv) {
|
||||
thread_active=false;
|
||||
@ -560,7 +558,6 @@ SystemExec::output_interposer()
|
||||
ReadStdout(rv, bytesRead); /* EMIT SIGNAL */
|
||||
}
|
||||
Terminated(); /* EMIT SIGNAL */
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -808,7 +805,7 @@ SystemExec::start (StdErrMode stderr_mode, const char *vfork_exec_wrapper)
|
||||
close_fd (pout[1]);
|
||||
close_fd (pin[0]);
|
||||
|
||||
int rv = pthread_create (&thread_id_tt, NULL, interposer_thread, this);
|
||||
int rv = pthread_create_and_store ("ExecStdOut", &thread_id_tt, interposer_thread, this, 0);
|
||||
thread_active=true;
|
||||
|
||||
if (rv) {
|
||||
@ -917,7 +914,6 @@ again:
|
||||
ReadStdout (rv, r); /* EMIT SIGNAL */
|
||||
}
|
||||
Terminated (); /* EMIT SIGNAL */
|
||||
pthread_exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -258,8 +258,6 @@ CC121::stop ()
|
||||
void
|
||||
CC121::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -238,8 +238,6 @@ void
|
||||
ContourDesignControlProtocol::thread_init ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::ContourDesignControl, "thread_init()\n");
|
||||
|
||||
pthread_set_name (X_("contourdesign"));
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("contourdesign"), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (X_("contourdesign"), 128);
|
||||
|
||||
|
@ -283,8 +283,6 @@ FaderPort8::stop ()
|
||||
void
|
||||
FaderPort8::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -308,8 +308,6 @@ GenericMidiControlProtocol::stop ()
|
||||
void
|
||||
GenericMidiControlProtocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -665,8 +665,6 @@ void LaunchControlXL::handle_midi_note_off_message(MIDI::Parser & parser, MIDI::
|
||||
void
|
||||
LaunchControlXL::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -194,8 +194,6 @@ MackieControlProtocol::~MackieControlProtocol()
|
||||
void
|
||||
MackieControlProtocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -307,16 +307,9 @@ Maschine2::stop ()
|
||||
void
|
||||
Maschine2::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 1024);
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 1024);
|
||||
|
||||
struct sched_param rtparam;
|
||||
memset (&rtparam, 0, sizeof (rtparam));
|
||||
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
|
||||
if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
|
||||
// do we care? not particularly.
|
||||
}
|
||||
set_thread_priority ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -284,8 +284,6 @@ OSC::start ()
|
||||
void
|
||||
OSC::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
if (_osc_unix_server) {
|
||||
Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
|
||||
src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_unix_server));
|
||||
|
@ -174,8 +174,6 @@ US2400Protocol::~US2400Protocol()
|
||||
void
|
||||
US2400Protocol::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name().c_str());
|
||||
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
|
||||
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
|
||||
|
||||
|
@ -76,7 +76,6 @@ ArdourWebsockets::set_active (bool yn)
|
||||
void
|
||||
ArdourWebsockets::thread_init ()
|
||||
{
|
||||
pthread_set_name (event_loop_name ().c_str ());
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), event_loop_name (), 2048);
|
||||
SessionEvent::create_per_thread_pool (event_loop_name (), 128);
|
||||
}
|
||||
|
@ -154,8 +154,6 @@ WiimoteControlProtocol::thread_init ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init init\n");
|
||||
|
||||
pthread_set_name (X_("wiimote"));
|
||||
|
||||
// allow to make requests to the GUI and RT thread(s)
|
||||
PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("wiimote"), 2048);
|
||||
BasicUI::register_thread ("wiimote");
|
||||
|
@ -229,6 +229,9 @@ gdk_event_mask_get_type (void)
|
||||
{ GDK_PROXIMITY_OUT_MASK, "GDK_PROXIMITY_OUT_MASK", "proximity-out-mask" },
|
||||
{ GDK_SUBSTRUCTURE_MASK, "GDK_SUBSTRUCTURE_MASK", "substructure-mask" },
|
||||
{ GDK_SCROLL_MASK, "GDK_SCROLL_MASK", "scroll-mask" },
|
||||
{ GDK_TOUCH_BEGIN_MASK, "GDK_TOUCH_BEGIN_MASK", "touch-begin-mask" },
|
||||
{ GDK_TOUCH_UPDATE_MASK, "GDK_TOUCH_UPDATE_MASK", "touch-update-mask" },
|
||||
{ GDK_TOUCH_END_MASK, "GDK_TOUCH_END_MASK", "touch-end-mask" },
|
||||
{ GDK_ALL_EVENTS_MASK, "GDK_ALL_EVENTS_MASK", "all-events-mask" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
@ -387,6 +387,14 @@ gdk_event_new (GdkEventType type)
|
||||
new_event->button.x_root = 0.;
|
||||
new_event->button.y_root = 0.;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
new_event->touch.x = 0.;
|
||||
new_event->touch.y = 0.;
|
||||
new_event->touch.x_root = 0.;
|
||||
new_event->touch.y_root = 0.;
|
||||
break;
|
||||
case GDK_SCROLL:
|
||||
new_event->scroll.x = 0.;
|
||||
new_event->scroll.y = 0.;
|
||||
@ -596,6 +604,10 @@ gdk_event_get_time (const GdkEvent *event)
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
return event->button.time;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
return event->touch.time;
|
||||
case GDK_SCROLL:
|
||||
return event->scroll.time;
|
||||
case GDK_KEY_PRESS:
|
||||
@ -674,6 +686,11 @@ gdk_event_get_state (const GdkEvent *event,
|
||||
case GDK_BUTTON_RELEASE:
|
||||
*state = event->button.state;
|
||||
return TRUE;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
*state = event->touch.state;
|
||||
return TRUE;
|
||||
case GDK_SCROLL:
|
||||
*state = event->scroll.state;
|
||||
return TRUE;
|
||||
@ -770,6 +787,12 @@ gdk_event_get_coords (const GdkEvent *event,
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
x = event->touch.x;
|
||||
y = event->touch.y;
|
||||
break;
|
||||
default:
|
||||
fetched = FALSE;
|
||||
break;
|
||||
@ -820,6 +843,12 @@ gdk_event_get_root_coords (const GdkEvent *event,
|
||||
x = event->button.x_root;
|
||||
y = event->button.y_root;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
x = event->touch.x_root;
|
||||
y = event->touch.y_root;
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
x = event->crossing.x_root;
|
||||
|
@ -9887,6 +9887,9 @@ static const guint type_masks[] = {
|
||||
0, /* GDK_OWNER_CHANGE = 34 */
|
||||
0, /* GDK_GRAB_BROKEN = 35 */
|
||||
0, /* GDK_DAMAGE = 36 */
|
||||
GDK_TOUCH_BEGIN_MASK, /* GDK_TOUCH_BEGIN = 37 */
|
||||
GDK_TOUCH_UPDATE_MASK, /* GDK_TOUCH_UPDATE = 38 */
|
||||
GDK_TOUCH_END_MASK, /* GDK_TOUCH_END = 39 */
|
||||
};
|
||||
G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
|
||||
|
||||
@ -9929,6 +9932,14 @@ is_motion_type (GdkEventType type)
|
||||
type == GDK_LEAVE_NOTIFY;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_touch_type (GdkEventType type)
|
||||
{
|
||||
return type == GDK_TOUCH_BEGIN ||
|
||||
type == GDK_TOUCH_UPDATE ||
|
||||
type == GDK_TOUCH_END;
|
||||
}
|
||||
|
||||
static GdkWindowObject *
|
||||
find_common_ancestor (GdkWindowObject *win1,
|
||||
GdkWindowObject *win2)
|
||||
@ -10828,6 +10839,8 @@ proxy_button_event (GdkEvent *source_event,
|
||||
_gdk_display_pointer_grab_update (display, serial);
|
||||
}
|
||||
|
||||
// TODO pointer grab per touch event (use g hash table)
|
||||
|
||||
pointer_window = get_pointer_window (display, toplevel_window,
|
||||
toplevel_x, toplevel_y,
|
||||
serial);
|
||||
@ -10873,6 +10886,19 @@ proxy_button_event (GdkEvent *source_event,
|
||||
event->scroll.delta_y = source_event->scroll.delta_y;
|
||||
return TRUE;
|
||||
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
toplevel_x, toplevel_y,
|
||||
&event->touch.x, &event->touch.y);
|
||||
event->touch.sequence = source_event->touch.sequence;
|
||||
event->touch.deviceid = source_event->touch.deviceid;
|
||||
event->touch.x_root = source_event->touch.x_root;
|
||||
event->touch.y_root = source_event->touch.y_root;
|
||||
event->touch.state = state;
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
@ -11057,7 +11083,8 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
return;
|
||||
|
||||
if (!(is_button_type (event->type) ||
|
||||
is_motion_type (event->type)) ||
|
||||
is_motion_type (event->type) ||
|
||||
is_touch_type (event->type)) ||
|
||||
event_private->window_type == GDK_WINDOW_ROOT)
|
||||
return;
|
||||
|
||||
@ -11147,6 +11174,9 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
else if (is_button_type (event->type))
|
||||
unlink_event = proxy_button_event (event,
|
||||
serial);
|
||||
else if (is_touch_type (event->type))
|
||||
unlink_event = proxy_button_event (event,
|
||||
serial);
|
||||
|
||||
if (event->type == GDK_BUTTON_RELEASE &&
|
||||
!event->any.send_event)
|
||||
|
@ -811,6 +811,10 @@ _gdk_win32_print_event (const GdkEvent *event)
|
||||
CASE (GDK_SETTING);
|
||||
CASE (GDK_OWNER_CHANGE);
|
||||
CASE (GDK_GRAB_BROKEN);
|
||||
CASE (GDK_TOUCH_BEGIN);
|
||||
CASE (GDK_TOUCH_UPDATE);
|
||||
CASE (GDK_TOUCH_END);
|
||||
CASE (GDK_TOUCH_CANCEL);
|
||||
#undef CASE
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
@ -935,6 +939,7 @@ _gdk_win32_print_event (const GdkEvent *event)
|
||||
g_print ("%s: %s",
|
||||
_gdk_win32_window_state_to_string (event->window_state.changed_mask),
|
||||
_gdk_win32_window_state_to_string (event->window_state.new_window_state));
|
||||
break;
|
||||
case GDK_SETTING:
|
||||
g_print ("%s: %s",
|
||||
(event->setting.action == GDK_SETTING_ACTION_NEW ? "NEW" :
|
||||
@ -942,11 +947,23 @@ _gdk_win32_print_event (const GdkEvent *event)
|
||||
(event->setting.action == GDK_SETTING_ACTION_DELETED ? "DELETED" :
|
||||
"???"))),
|
||||
(event->setting.name ? event->setting.name : "NULL"));
|
||||
break;
|
||||
case GDK_GRAB_BROKEN:
|
||||
g_print ("%s %s %p",
|
||||
(event->grab_broken.keyboard ? "KEYBOARD" : "POINTER"),
|
||||
(event->grab_broken.implicit ? "IMPLICIT" : "EXPLICIT"),
|
||||
(event->grab_broken.grab_window ? GDK_WINDOW_HWND (event->grab_broken.grab_window) : 0));
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
g_print ("Touch %s %d (%.4g,%.4g) (%.4g,%.4g) ",
|
||||
(event->any.type == GDK_TOUCH_BEGIN) ? "Begin" : (event->any.type == GDK_TOUCH_END) ? "End" : "Update",
|
||||
event->touch.sequence,
|
||||
event->touch.x, event->touch.y,
|
||||
event->touch.x_root, event->touch.y_root);
|
||||
case GDK_TOUCH_CANCEL:
|
||||
g_print ("Touch Cancel\n");
|
||||
default:
|
||||
/* Nothing */
|
||||
break;
|
||||
@ -2681,6 +2698,13 @@ gdk_event_translate (MSG *msg,
|
||||
return_val = TRUE;
|
||||
break;
|
||||
|
||||
case WM_POINTERDOWN:
|
||||
break;
|
||||
case WM_POINTERUP:
|
||||
break;
|
||||
case WM_POINTERUPDATE:
|
||||
break;
|
||||
|
||||
case WM_NCMOUSEMOVE:
|
||||
GDK_NOTE (EVENTS,
|
||||
g_print (" (%d,%d)",
|
||||
|
@ -164,6 +164,7 @@ def configure(conf):
|
||||
conf.check_cc(header_name='X11/extensions/Xinerama.h',
|
||||
lib='Xinerama', uselib_store="XINERAMA", define_name='HAVE_XFREE_XINERAMA',
|
||||
execute = False, mandatory=False)
|
||||
autowaf.check_pkg(conf, 'xi', uselib_store='XINPUT2', mandatory=False, atleast_version='1.7.10')
|
||||
|
||||
def build(bld):
|
||||
if not bld.is_defined('YTK'):
|
||||
@ -202,7 +203,7 @@ def build(bld):
|
||||
obj.ldflags = '-limm32 -lole32 -lgdi32 -lcomdlg32 -lwinspool -lcomctl32 -luuid'
|
||||
else:
|
||||
obj.source = libydk_sources + libydk_x11_sources
|
||||
obj.uselib += ' GIO-UNIX X11 XEXT XINERAMA RANDR'
|
||||
obj.uselib += ' GIO-UNIX X11 XEXT XINERAMA RANDR DL'
|
||||
obj.includes += ['ydk/x11/gdk', 'ydk/gdk/x11']
|
||||
obj.export_includes += ['ydk/gdk']
|
||||
obj.export_includes += ['ydk/x11']
|
||||
|
@ -65,6 +65,9 @@
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
static void gdk_display_x11_dispose (GObject *object);
|
||||
static void gdk_display_x11_finalize (GObject *object);
|
||||
@ -864,6 +867,13 @@ gdk_display_x11_finalize (GObject *object)
|
||||
g_hash_table_destroy (display_x11->atom_from_virtual);
|
||||
g_hash_table_destroy (display_x11->atom_to_virtual);
|
||||
|
||||
/* Multitouch */
|
||||
#ifdef HAVE_XINPUT2
|
||||
if (display_x11->xi.libxi)
|
||||
dlclose (display_x11->xi.libxi);
|
||||
g_hash_table_destroy (display_x11->touch_devices);
|
||||
#endif
|
||||
|
||||
/* Leader Window */
|
||||
XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
|
||||
|
||||
|
@ -62,6 +62,11 @@
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <dlfcn.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
typedef struct _GdkIOClosure GdkIOClosure;
|
||||
@ -237,6 +242,64 @@ _gdk_events_init (GdkDisplay *display)
|
||||
gdk_atom_intern_static_string ("WM_PROTOCOLS"),
|
||||
gdk_wm_protocols_filter,
|
||||
NULL);
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
void* lxi = dlopen ("libXi.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (lxi)
|
||||
{
|
||||
display_x11->xi.XISelectEvents = dlsym (lxi, "XISelectEvents");
|
||||
display_x11->xi.XIQueryDevice = dlsym (lxi, "XIQueryDevice");
|
||||
display_x11->xi.XIFreeDeviceInfo = dlsym (lxi, "XIFreeDeviceInfo");
|
||||
if (display_x11->xi.XISelectEvents && display_x11->xi.XIQueryDevice && display_x11->xi.XIFreeDeviceInfo)
|
||||
{
|
||||
display_x11->xi.libxi = lxi;
|
||||
}
|
||||
else
|
||||
{
|
||||
dlclose (lxi);
|
||||
}
|
||||
}
|
||||
|
||||
int firstevent, firsterror;
|
||||
if (display_x11->xi.libxi && XQueryExtension (display_x11->xdisplay, "XInputExtension", &display_x11->xid_opcode, &firstevent, &firsterror))
|
||||
{
|
||||
printf ("CHECK FOR TOUCHSCREENs\n");
|
||||
|
||||
int n_devices;
|
||||
XIDeviceInfo* info;
|
||||
|
||||
info = display_x11->xi.XIQueryDevice (display_x11->xdisplay, XIAllDevices, &n_devices);
|
||||
|
||||
for (int i = 0; i < n_devices; ++i) {
|
||||
XIDeviceInfo* dev = &info[i];
|
||||
if (!dev->enabled) {
|
||||
continue;
|
||||
}
|
||||
if (!(dev->use == XISlavePointer || dev->use == XIFloatingSlave)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gboolean direct_touch = FALSE;
|
||||
XITouchClassInfo* classInfo;
|
||||
|
||||
for (int j = 0; j < dev->num_classes; ++j) {
|
||||
classInfo = (XITouchClassInfo*)(dev->classes[j]);
|
||||
|
||||
if (classInfo->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
|
||||
direct_touch = TRUE;
|
||||
}
|
||||
}
|
||||
if (direct_touch) {
|
||||
printf ("XI: touch-device id=%d name='%s' ntouch: %d\n", dev->deviceid, dev->name, classInfo->num_touches);
|
||||
if (!display_x11->touch_devices) {
|
||||
display_x11->touch_devices = g_hash_table_new (g_direct_hash, NULL);
|
||||
}
|
||||
g_hash_table_insert (display_x11->touch_devices, GUINT_TO_POINTER (dev->deviceid), GUINT_TO_POINTER(1));
|
||||
}
|
||||
}
|
||||
display_x11->xi.XIFreeDeviceInfo (info);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -1233,7 +1296,7 @@ gdk_event_translate (GdkDisplay *display,
|
||||
event->button.state = (GdkModifierType) xevent->xbutton.state;
|
||||
event->button.button = xevent->xbutton.button;
|
||||
event->button.device = display->core_pointer;
|
||||
|
||||
|
||||
if (!set_screen_from_root (display, event, xevent->xbutton.root))
|
||||
{
|
||||
return_val = FALSE;
|
||||
@ -2124,6 +2187,9 @@ gdk_event_translate (GdkDisplay *display,
|
||||
break;
|
||||
|
||||
default:
|
||||
if (xevent->xcookie.type == GenericEvent) {
|
||||
XGetEventData (display_x11->xdisplay, &xevent->xcookie);
|
||||
}
|
||||
#ifdef HAVE_XKB
|
||||
if (xevent->type == display_x11->xkb_event_type)
|
||||
{
|
||||
@ -2175,6 +2241,46 @@ gdk_event_translate (GdkDisplay *display,
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_XINPUT2
|
||||
if (xevent->xcookie.type == GenericEvent && xevent->xcookie.extension == display_x11->xid_opcode
|
||||
&& display_x11->touch_devices && g_hash_table_lookup (display_x11->touch_devices, GUINT_TO_POINTER (((XIDeviceEvent *)xevent->xcookie.data)->deviceid)))
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) xevent->xcookie.data;
|
||||
printf ("TOUCH dev=%d src=%d | dt: %u flags: %x\n", xev->deviceid, xev->sourceid, xev->detail, xev->flags);
|
||||
window = gdk_window_lookup_for_display (display, xev->event);
|
||||
g_object_ref (window);
|
||||
|
||||
event->touch.window = window;
|
||||
event->touch.time = xev->time;
|
||||
event->touch.x = xev->event_x;
|
||||
event->touch.y = xev->event_y;
|
||||
event->touch.x_root = xev->root_x;
|
||||
event->touch.y_root = xev->root_y;
|
||||
event->touch.state = 0 ; (GdkModifierType) xevent->xbutton.state;
|
||||
event->touch.sequence = xev->detail;
|
||||
event->touch.deviceid = xev->deviceid;
|
||||
|
||||
switch (xevent->xcookie.evtype) {
|
||||
case XI_TouchBegin:
|
||||
event->touch.type = GDK_TOUCH_BEGIN;
|
||||
break;
|
||||
case XI_TouchUpdate:
|
||||
event->touch.type = GDK_TOUCH_UPDATE;
|
||||
break;
|
||||
case XI_TouchEnd:
|
||||
event->touch.type = GDK_TOUCH_END;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!set_screen_from_root (display, event, xev->root)) {
|
||||
return_val = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
|
||||
if (display_x11->have_xdamage && window_private && window_private->composited &&
|
||||
xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
|
||||
|
@ -71,6 +71,10 @@
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
const int _gdk_event_mask_table[21] =
|
||||
{
|
||||
ExposureMask,
|
||||
@ -797,6 +801,24 @@ _gdk_window_impl_new (GdkWindow *window,
|
||||
g_object_ref (window);
|
||||
_gdk_xid_table_insert (screen_x11->display, &draw_impl->xid, window);
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
|
||||
if (display_x11->touch_devices)
|
||||
{
|
||||
XIEventMask evmask;
|
||||
unsigned char mask[XIMaskLen(XI_LASTEVENT)] = { 0 };
|
||||
evmask.deviceid = XIAllDevices;
|
||||
evmask.mask_len = sizeof(mask);
|
||||
evmask.mask = mask;
|
||||
|
||||
XISetMask(evmask.mask, XI_TouchBegin);
|
||||
XISetMask(evmask.mask, XI_TouchUpdate);
|
||||
XISetMask(evmask.mask, XI_TouchEnd);
|
||||
|
||||
display_x11->xi.XISelectEvents (xdisplay, xid, &evmask, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (GDK_WINDOW_TYPE (private))
|
||||
{
|
||||
case GDK_WINDOW_DIALOG:
|
||||
|
@ -50,6 +50,7 @@ typedef struct _GdkEventNoExpose GdkEventNoExpose;
|
||||
typedef struct _GdkEventVisibility GdkEventVisibility;
|
||||
typedef struct _GdkEventMotion GdkEventMotion;
|
||||
typedef struct _GdkEventButton GdkEventButton;
|
||||
typedef struct _GdkEventTouch GdkEventTouch;
|
||||
typedef struct _GdkEventScroll GdkEventScroll;
|
||||
typedef struct _GdkEventKey GdkEventKey;
|
||||
typedef struct _GdkEventFocus GdkEventFocus;
|
||||
@ -152,6 +153,9 @@ typedef enum
|
||||
GDK_OWNER_CHANGE = 34,
|
||||
GDK_GRAB_BROKEN = 35,
|
||||
GDK_DAMAGE = 36,
|
||||
GDK_TOUCH_BEGIN = 37,
|
||||
GDK_TOUCH_UPDATE = 38,
|
||||
GDK_TOUCH_END = 39,
|
||||
GDK_EVENT_LAST /* helper variable for decls */
|
||||
} GdkEventType;
|
||||
|
||||
@ -181,6 +185,9 @@ typedef enum
|
||||
GDK_PROXIMITY_OUT_MASK = 1 << 19,
|
||||
GDK_SUBSTRUCTURE_MASK = 1 << 20,
|
||||
GDK_SCROLL_MASK = 1 << 21,
|
||||
GDK_TOUCH_BEGIN_MASK = 1 << 22,
|
||||
GDK_TOUCH_UPDATE_MASK = 1 << 23,
|
||||
GDK_TOUCH_END_MASK = 1 << 24,
|
||||
GDK_ALL_EVENTS_MASK = 0x3FFFFE
|
||||
} GdkEventMask;
|
||||
|
||||
@ -325,6 +332,20 @@ struct _GdkEventButton
|
||||
gdouble x_root, y_root;
|
||||
};
|
||||
|
||||
struct _GdkEventTouch
|
||||
{
|
||||
GdkEventType type;
|
||||
GdkWindow *window;
|
||||
gint8 send_event;
|
||||
guint32 time;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
guint state;
|
||||
guint sequence;
|
||||
guint deviceid;
|
||||
gdouble x_root, y_root;
|
||||
};
|
||||
|
||||
struct _GdkEventScroll
|
||||
{
|
||||
GdkEventType type;
|
||||
@ -500,6 +521,7 @@ union _GdkEvent
|
||||
GdkEventVisibility visibility;
|
||||
GdkEventMotion motion;
|
||||
GdkEventButton button;
|
||||
GdkEventTouch touch;
|
||||
GdkEventScroll scroll;
|
||||
GdkEventKey key;
|
||||
GdkEventCrossing crossing;
|
||||
|
@ -36,6 +36,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GdkDisplayX11 GdkDisplayX11;
|
||||
typedef struct _GdkXInput2Fn GdkXInput2Fn;
|
||||
typedef struct _GdkDisplayX11Class GdkDisplayX11Class;
|
||||
|
||||
#define GDK_TYPE_DISPLAY_X11 (_gdk_display_x11_get_type())
|
||||
@ -52,6 +53,19 @@ typedef enum
|
||||
GDK_YES
|
||||
} GdkTristate;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
struct _GdkXInput2Fn
|
||||
{
|
||||
int (*XISelectEvents)(Display*, Window, XIEventMask*, int);
|
||||
XIDeviceInfo* (*XIQueryDevice)(Display*, int, int*);
|
||||
void (*XIFreeDeviceInfo)(XIDeviceInfo*);
|
||||
void* libxi;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct _GdkDisplayX11
|
||||
{
|
||||
GdkDisplay parent_instance;
|
||||
@ -155,6 +169,12 @@ struct _GdkDisplayX11
|
||||
|
||||
/* The offscreen window that has the pointer in it (if any) */
|
||||
GdkWindow *active_offscreen_window;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
int xid_opcode;
|
||||
GHashTable* touch_devices;
|
||||
GdkXInput2Fn xi;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _GdkDisplayX11Class
|
||||
|
@ -92,6 +92,9 @@ enum EventType
|
||||
OWNER_CHANGE,
|
||||
GRAB_BROKEN,
|
||||
DAMAGE,
|
||||
TOUCH_BEGIN,
|
||||
TOUCH_UPDATE,
|
||||
TOUCH_END,
|
||||
EVENT_LAST
|
||||
};
|
||||
|
||||
|
@ -91,6 +91,9 @@ enum EventMask
|
||||
PROXIMITY_OUT_MASK = 1 << 19,
|
||||
SUBSTRUCTURE_MASK = 1 << 20,
|
||||
SCROLL_MASK = 1 << 21,
|
||||
TOUCH_BEGIN_MASK = 1 << 22,
|
||||
TOUCH_UPDATE_MASK = 1 << 23,
|
||||
TOUCH_END_MASK = 1 << 24,
|
||||
ALL_EVENTS_MASK = 0x3FFFFE
|
||||
};
|
||||
|
||||
|
@ -1599,6 +1599,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_TOUCH_BEGIN:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@ -1636,6 +1637,8 @@ gtk_main_do_event (GdkEvent *event)
|
||||
/* else fall through */
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
|
@ -197,6 +197,9 @@ enum {
|
||||
KEYNAV_FAILED,
|
||||
DRAG_FAILED,
|
||||
DAMAGE_EVENT,
|
||||
TOUCH_BEGIN,
|
||||
TOUCH_UPDATE,
|
||||
TOUCH_END,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -537,6 +540,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
klass->drag_drop = NULL;
|
||||
klass->drag_data_received = NULL;
|
||||
klass->screen_changed = NULL;
|
||||
klass->touch_begin_event = NULL;
|
||||
klass->touch_update_event = NULL;
|
||||
klass->touch_end_event = NULL;
|
||||
klass->can_activate_accel = gtk_widget_real_can_activate_accel;
|
||||
klass->grab_broken_event = NULL;
|
||||
klass->query_tooltip = gtk_widget_real_query_tooltip;
|
||||
@ -2377,6 +2383,39 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_SCREEN);
|
||||
|
||||
|
||||
/* YTK Touch */
|
||||
widget_signals[TOUCH_BEGIN] =
|
||||
g_signal_new (I_("touch-start"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, touch_begin_event),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__BOXED,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
widget_signals[TOUCH_UPDATE] =
|
||||
g_signal_new (I_("touch-update"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, touch_update_event),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__BOXED,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
widget_signals[TOUCH_END] =
|
||||
g_signal_new (I_("touch-end"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, touch_end_event),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__BOXED,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
|
||||
/**
|
||||
* GtkWidget::can-activate-accel:
|
||||
* @widget: the object which received the signal
|
||||
@ -5001,6 +5040,15 @@ gtk_widget_event_internal (GtkWidget *widget,
|
||||
case GDK_DAMAGE:
|
||||
signal_num = DAMAGE_EVENT;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
signal_num = TOUCH_BEGIN;
|
||||
break;
|
||||
case GDK_TOUCH_END:
|
||||
signal_num = TOUCH_END;
|
||||
break;
|
||||
case GDK_TOUCH_UPDATE:
|
||||
signal_num = TOUCH_UPDATE;
|
||||
break;
|
||||
default:
|
||||
g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
|
||||
signal_num = -1;
|
||||
|
@ -726,6 +726,12 @@ struct _GtkWidgetClass
|
||||
GdkEventAny *event);
|
||||
gboolean (* window_state_event) (GtkWidget *widget,
|
||||
GdkEventWindowState *event);
|
||||
gboolean (* touch_begin_event) (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
gboolean (* touch_update_event) (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
gboolean (* touch_end_event) (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
|
||||
/* selection */
|
||||
void (* selection_get) (GtkWidget *widget,
|
||||
|
@ -3395,6 +3395,9 @@ void Widget_Class::class_init_function(void* g_class, void* class_data)
|
||||
klass->drag_motion = &drag_motion_callback;
|
||||
klass->drag_drop = &drag_drop_callback;
|
||||
klass->drag_data_received = &drag_data_received_callback;
|
||||
klass->touch_begin_event = &touch_begin_callback;
|
||||
klass->touch_update_event = &touch_update_callback;
|
||||
klass->touch_end_event = &touch_end_callback;
|
||||
#ifdef GTKMM_ATKMM_ENABLED
|
||||
#ifndef GTKMM_DISABLE_DEPRECATED
|
||||
|
||||
@ -4344,6 +4347,120 @@ gboolean Widget_Class::button_release_event_callback(GtkWidget* self, GdkEventBu
|
||||
typedef gboolean RType;
|
||||
return RType();
|
||||
}
|
||||
gboolean Widget_Class::touch_begin_callback(GtkWidget* self, GdkEventTouch* p0)
|
||||
{
|
||||
Glib::ObjectBase *const obj_base = static_cast<Glib::ObjectBase*>(
|
||||
Glib::ObjectBase::_get_current_wrapper((GObject*)self));
|
||||
|
||||
// Non-gtkmmproc-generated custom classes implicitly call the default
|
||||
// Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
|
||||
// generated classes can use this optimisation, which avoids the unnecessary
|
||||
// parameter conversions if there is no possibility of the virtual function
|
||||
// being overridden:
|
||||
if(obj_base && obj_base->is_derived_())
|
||||
{
|
||||
CppObjectType *const obj = dynamic_cast<CppObjectType* const>(obj_base);
|
||||
if(obj) // This can be NULL during destruction.
|
||||
{
|
||||
try // Trap C++ exceptions which would normally be lost because this is a C callback.
|
||||
{
|
||||
// Call the virtual member method, which derived classes might override.
|
||||
return static_cast<int>(obj->on_touch_begin_event(p0));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
// Call the original underlying C function:
|
||||
if(base && base->touch_begin_event)
|
||||
return (*base->touch_begin_event)(self, p0);
|
||||
|
||||
typedef gboolean RType;
|
||||
return RType();
|
||||
}
|
||||
gboolean Widget_Class::touch_update_callback(GtkWidget* self, GdkEventTouch* p0)
|
||||
{
|
||||
Glib::ObjectBase *const obj_base = static_cast<Glib::ObjectBase*>(
|
||||
Glib::ObjectBase::_get_current_wrapper((GObject*)self));
|
||||
|
||||
// Non-gtkmmproc-generated custom classes implicitly call the default
|
||||
// Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
|
||||
// generated classes can use this optimisation, which avoids the unnecessary
|
||||
// parameter conversions if there is no possibility of the virtual function
|
||||
// being overridden:
|
||||
if(obj_base && obj_base->is_derived_())
|
||||
{
|
||||
CppObjectType *const obj = dynamic_cast<CppObjectType* const>(obj_base);
|
||||
if(obj) // This can be NULL during destruction.
|
||||
{
|
||||
try // Trap C++ exceptions which would normally be lost because this is a C callback.
|
||||
{
|
||||
// Call the virtual member method, which derived classes might override.
|
||||
return static_cast<int>(obj->on_touch_update_event(p0));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
// Call the original underlying C function:
|
||||
if(base && base->touch_update_event)
|
||||
return (*base->touch_update_event)(self, p0);
|
||||
|
||||
typedef gboolean RType;
|
||||
return RType();
|
||||
}
|
||||
gboolean Widget_Class::touch_end_callback(GtkWidget* self, GdkEventTouch* p0)
|
||||
{
|
||||
Glib::ObjectBase *const obj_base = static_cast<Glib::ObjectBase*>(
|
||||
Glib::ObjectBase::_get_current_wrapper((GObject*)self));
|
||||
|
||||
// Non-gtkmmproc-generated custom classes implicitly call the default
|
||||
// Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
|
||||
// generated classes can use this optimisation, which avoids the unnecessary
|
||||
// parameter conversions if there is no possibility of the virtual function
|
||||
// being overridden:
|
||||
if(obj_base && obj_base->is_derived_())
|
||||
{
|
||||
CppObjectType *const obj = dynamic_cast<CppObjectType* const>(obj_base);
|
||||
if(obj) // This can be NULL during destruction.
|
||||
{
|
||||
try // Trap C++ exceptions which would normally be lost because this is a C callback.
|
||||
{
|
||||
// Call the virtual member method, which derived classes might override.
|
||||
return static_cast<int>(obj->on_touch_end_event(p0));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
// Call the original underlying C function:
|
||||
if(base && base->touch_end_event)
|
||||
return (*base->touch_end_event)(self, p0);
|
||||
|
||||
typedef gboolean RType;
|
||||
return RType();
|
||||
}
|
||||
gboolean Widget_Class::scroll_event_callback(GtkWidget* self, GdkEventScroll* p0)
|
||||
{
|
||||
Glib::ObjectBase *const obj_base = static_cast<Glib::ObjectBase*>(
|
||||
@ -7516,6 +7633,42 @@ bool Gtk::Widget::on_button_release_event(GdkEventButton* event)
|
||||
typedef bool RType;
|
||||
return RType();
|
||||
}
|
||||
bool Gtk::Widget::on_touch_begin_event(GdkEventTouch* event)
|
||||
{
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
if(base && base->touch_begin_event)
|
||||
return (*base->touch_begin_event)(gobj(),event);
|
||||
|
||||
typedef bool RType;
|
||||
return RType();
|
||||
}
|
||||
bool Gtk::Widget::on_touch_update_event(GdkEventTouch* event)
|
||||
{
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
if(base && base->touch_update_event)
|
||||
return (*base->touch_update_event)(gobj(),event);
|
||||
|
||||
typedef bool RType;
|
||||
return RType();
|
||||
}
|
||||
bool Gtk::Widget::on_touch_end_event(GdkEventTouch* event)
|
||||
{
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
|
||||
);
|
||||
|
||||
if(base && base->touch_end_event)
|
||||
return (*base->touch_end_event)(gobj(),event);
|
||||
|
||||
typedef bool RType;
|
||||
return RType();
|
||||
}
|
||||
bool Gtk::Widget::on_scroll_event(GdkEventScroll* event)
|
||||
{
|
||||
BaseClassType *const base = static_cast<BaseClassType*>(
|
||||
|
@ -90,6 +90,9 @@ protected:
|
||||
static gboolean drag_motion_callback(GtkWidget* self, GdkDragContext* p0, gint p1, gint p2, guint p3);
|
||||
static gboolean drag_drop_callback(GtkWidget* self, GdkDragContext* p0, gint p1, gint p2, guint p3);
|
||||
static void drag_data_received_callback(GtkWidget* self, GdkDragContext* p0, gint p1, gint p2, GtkSelectionData* p3, guint p4, guint p5);
|
||||
static gboolean touch_begin_callback(GtkWidget*, GdkEventTouch*);
|
||||
static gboolean touch_update_callback(GtkWidget*, GdkEventTouch*);
|
||||
static gboolean touch_end_callback(GtkWidget*, GdkEventTouch*);
|
||||
#ifdef GTKMM_ATKMM_ENABLED
|
||||
#ifndef GTKMM_DISABLE_DEPRECATED
|
||||
|
||||
|
@ -490,6 +490,9 @@ protected:
|
||||
virtual bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
|
||||
/// This is a default handler for the signal signal_drag_data_received().
|
||||
virtual void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const SelectionData& selection_data, guint info, guint time);
|
||||
virtual bool on_touch_begin_event(GdkEventTouch* event);
|
||||
virtual bool on_touch_update_event(GdkEventTouch* event);
|
||||
virtual bool on_touch_end_event(GdkEventTouch* event);
|
||||
#ifdef GTKMM_ATKMM_ENABLED
|
||||
/// This is a default handler for the signal signal_get_accessible().
|
||||
virtual Glib::RefPtr<Atk::Object> on_get_accessible();
|
||||
|
@ -309,6 +309,11 @@ WaveView::get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect
|
||||
double const width = region_length() / _props->samples_per_pixel;
|
||||
item_rect = item_to_window (Rect (0.0, 0.0, width, _props->height), false);
|
||||
|
||||
item_rect.x0 = floor (item_rect.x0);
|
||||
item_rect.x1 = ceil (item_rect.x1);
|
||||
item_rect.y0 = round (item_rect.y0);
|
||||
item_rect.y1 = round (item_rect.y1);
|
||||
|
||||
/* Now lets get the intersection with the area we've been asked to draw */
|
||||
|
||||
draw_rect = item_rect.intersection (canvas_rect);
|
||||
@ -317,12 +322,6 @@ WaveView::get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect
|
||||
// No intersection with drawing area
|
||||
return false;
|
||||
}
|
||||
|
||||
item_rect.x0 = floor (item_rect.x0);
|
||||
item_rect.x1 = ceil (item_rect.x1);
|
||||
item_rect.y0 = round (item_rect.y0);
|
||||
item_rect.y1 = round (item_rect.y1);
|
||||
|
||||
/* draw_rect now defines the rectangle we need to update/render the waveview
|
||||
* into, in window coordinate space.
|
||||
*
|
||||
|
@ -405,7 +405,7 @@ WaveViewDrawingThread::start ()
|
||||
{
|
||||
assert (!_thread);
|
||||
|
||||
_thread = PBD::Thread::create (&WaveViewThreads::thread_proc);
|
||||
_thread = PBD::Thread::create (&WaveViewThreads::thread_proc, "WaveViewDrawing");
|
||||
}
|
||||
|
||||
void
|
||||
@ -477,8 +477,6 @@ WaveViewThreads::thread_proc ()
|
||||
void
|
||||
WaveViewThreads::_thread_proc ()
|
||||
{
|
||||
pthread_set_name ("WaveViewDrawing");
|
||||
|
||||
while (true) {
|
||||
|
||||
_queue_mutex.lock ();
|
||||
|
@ -103,6 +103,7 @@ ArdourButton::ArdourButton (Element e, bool toggle)
|
||||
UIConfigurationBase::instance().ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler));
|
||||
/* This is not provided by gtkmm */
|
||||
signal_grab_broken_event().connect (sigc::mem_fun (*this, &ArdourButton::on_grab_broken_event));
|
||||
add_events (Gdk::TOUCH_BEGIN_MASK | Gdk::TOUCH_END_MASK);
|
||||
}
|
||||
|
||||
ArdourButton::ArdourButton (const std::string& str, Element e, bool toggle)
|
||||
@ -154,6 +155,7 @@ ArdourButton::ArdourButton (const std::string& str, Element e, bool toggle)
|
||||
UIConfigurationBase::instance().DPIReset.connect (sigc::mem_fun (*this, &ArdourButton::on_name_changed));
|
||||
/* This is not provided by gtkmm */
|
||||
signal_grab_broken_event().connect (sigc::mem_fun (*this, &ArdourButton::on_grab_broken_event));
|
||||
add_events (Gdk::TOUCH_BEGIN_MASK | Gdk::TOUCH_END_MASK);
|
||||
}
|
||||
|
||||
ArdourButton::~ArdourButton()
|
||||
@ -943,6 +945,42 @@ ArdourButton::set_led_left (bool yn)
|
||||
_led_left = yn;
|
||||
}
|
||||
|
||||
bool
|
||||
ArdourButton::on_touch_begin_event (GdkEventTouch *ev)
|
||||
{
|
||||
printf ("ArdourButton::on_touch_begin_event finger %d\n", ev->sequence);
|
||||
focus_handler (this);
|
||||
|
||||
CairoWidget::set_dirty ();
|
||||
|
||||
if (!_act_on_release) {
|
||||
if (_action) {
|
||||
_action->activate ();
|
||||
} else if (_auto_toggle) {
|
||||
set_active (!get_active ());
|
||||
signal_clicked ();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ArdourButton::on_touch_end_event (GdkEventTouch *ev)
|
||||
{
|
||||
printf ("ArdourButton::on_touch_end_event finger: %d\n", ev->sequence);
|
||||
CairoWidget::set_dirty ();
|
||||
|
||||
if (_act_on_release && _auto_toggle && !_action) {
|
||||
set_active (!get_active ());
|
||||
}
|
||||
signal_clicked ();
|
||||
if (_act_on_release && _action) {
|
||||
_action->activate ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ArdourButton::on_button_press_event (GdkEventButton *ev)
|
||||
{
|
||||
|
@ -61,6 +61,8 @@ ArdourFader::ArdourFader (Gtk::Adjustment& adj, int orientation, int fader_lengt
|
||||
{
|
||||
update_unity_position ();
|
||||
|
||||
add_events (Gdk::TOUCH_UPDATE_MASK);
|
||||
|
||||
if (_orien == VERT) {
|
||||
CairoWidget::set_size_request(_girth, _span);
|
||||
} else {
|
||||
@ -464,6 +466,18 @@ ArdourFader::on_motion_notify_event (GdkEventMotion* ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ArdourFader::on_touch_update_event (GdkEventTouch* ev)
|
||||
{
|
||||
GdkEventMotion mev;
|
||||
mev.window = ev->window;
|
||||
mev.time = ev->time;
|
||||
mev.x = ev->x;
|
||||
mev.y = ev->y;
|
||||
mev.state = 0;
|
||||
return ArdourFader::on_motion_notify_event (&mev);
|
||||
}
|
||||
|
||||
/** @return pixel offset of the current value from the right or bottom of the fader */
|
||||
int
|
||||
ArdourFader::display_span ()
|
||||
|
@ -41,6 +41,8 @@ FaderWidget::FaderWidget (Gtk::Adjustment& adj, int orien)
|
||||
| Gdk::SCROLL_MASK
|
||||
| Gdk::ENTER_NOTIFY_MASK
|
||||
| Gdk::LEAVE_NOTIFY_MASK
|
||||
| Gdk::TOUCH_BEGIN_MASK
|
||||
| Gdk::TOUCH_END_MASK
|
||||
);
|
||||
|
||||
_adjustment.signal_value_changed().connect (mem_fun (*this, &FaderWidget::adjustment_changed));
|
||||
@ -100,6 +102,29 @@ FaderWidget::on_button_press_event (GdkEventButton* ev)
|
||||
return (_tweaks & NoButtonForward) ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
FaderWidget::on_touch_begin_event (GdkEventTouch *ev)
|
||||
{
|
||||
StartGesture (0);
|
||||
_grab_loc = (_orien == VERT) ? ev->y : ev->x;
|
||||
_grab_start = (_orien == VERT) ? ev->y : ev->x;
|
||||
_grab_window = ev->window;
|
||||
_dragging = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FaderWidget::on_touch_end_event (GdkEventTouch *ev)
|
||||
{
|
||||
if (!_dragging) {
|
||||
return true;
|
||||
}
|
||||
_dragging = false;
|
||||
StopGesture (0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FaderWidget::on_enter_notify_event (GdkEventCrossing*)
|
||||
{
|
||||
|
@ -124,6 +124,8 @@ class LIBWIDGETS_API ArdourButton : public CairoWidget , public Gtkmm2ext::Activ
|
||||
|
||||
bool on_button_press_event (GdkEventButton*);
|
||||
bool on_button_release_event (GdkEventButton*);
|
||||
bool on_touch_begin_event (GdkEventTouch*);
|
||||
bool on_touch_end_event (GdkEventTouch*);
|
||||
|
||||
void set_image (const Glib::RefPtr<Gdk::Pixbuf>&);
|
||||
|
||||
|
@ -55,6 +55,7 @@ protected:
|
||||
|
||||
void render (Cairo::RefPtr<Cairo::Context> const&, cairo_rectangle_t*);
|
||||
bool on_motion_notify_event (GdkEventMotion*);
|
||||
bool on_touch_update_event (GdkEventTouch*);
|
||||
|
||||
void on_state_changed (Gtk::StateType);
|
||||
void on_style_changed (const Glib::RefPtr<Gtk::Style>&);
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
protected:
|
||||
bool on_button_press_event (GdkEventButton*);
|
||||
bool on_button_release_event (GdkEventButton*);
|
||||
bool on_touch_begin_event (GdkEventTouch*);
|
||||
bool on_touch_end_event (GdkEventTouch*);
|
||||
bool on_enter_notify_event (GdkEventCrossing* ev);
|
||||
bool on_leave_notify_event (GdkEventCrossing* ev);
|
||||
bool on_scroll_event (GdkEventScroll* ev);
|
||||
|
Loading…
Reference in New Issue
Block a user