From 2293e357f477cefacaef3df141b36d14b4997e31 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Wed, 30 Apr 2014 10:38:48 +0000 Subject: [PATCH] Increased main window size a bit to avoid the iconview shift down each time an icon is selected. Added some scsi-output properties to full parser to avoid console warnings. Devices having only basic info can be displayed now in the info window. --- gsmartcontrol/TODO | 10 + .../src/applib/smartctl_executor.cpp | 2 +- gsmartcontrol/src/applib/smartctl_executor.h | 8 +- gsmartcontrol/src/applib/smartctl_parser.cpp | 25 +- .../src/applib/storage_detector_win32.cpp | 2 +- gsmartcontrol/src/applib/storage_device.cpp | 30 +- gsmartcontrol/src/applib/storage_device.h | 14 +- gsmartcontrol/src/applib/storage_property.h | 4 +- gsmartcontrol/src/gsc_info_window.cpp | 11 +- gsmartcontrol/src/gsc_main_window.cpp | 6 +- gsmartcontrol/src/hz/sync_policy_glib.h | 340 ++++++++++++------ gsmartcontrol/src/res/gsc_main_window.glade | 4 +- 12 files changed, 317 insertions(+), 139 deletions(-) diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index b5ce510..5bc1232 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -28,6 +28,12 @@ Bugs / patches: TODO: +Don't rely on smartctl return code (2), parse the output instead. + This will allow us to show the Info page. + +Update to latest drivedb. + + Test Areca windows detection by installing CLI, then replacing it with a dummy program that prints something (with enclosures and without). @@ -38,6 +44,10 @@ Fix not being able to quit while executing commands. https://developer.gnome.org/glib/2.34/glib-The-Main-Event-Loop.html#g-main-loop-quit +In main window add multi-selection support and right-click menu with various + tests, so that it's possible to run multiple tests in parallel from there. + + Areca detection Linux: Somehow differentiate between the cards with expanders (-d areca,N/E) and without (-d areca,N). diff --git a/gsmartcontrol/src/applib/smartctl_executor.cpp b/gsmartcontrol/src/applib/smartctl_executor.cpp index c7d1612..cfab020 100644 --- a/gsmartcontrol/src/applib/smartctl_executor.cpp +++ b/gsmartcontrol/src/applib/smartctl_executor.cpp @@ -111,7 +111,7 @@ std::string execute_smartctl(const std::string& device, const std::string& devic + " " + Glib::shell_quote(device)); if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) { - debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n"); + debug_out_warn("app", DBG_FUNC_MSG << "Smartctl binary did not execute cleanly.\n"); smartctl_output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str())); diff --git a/gsmartcontrol/src/applib/smartctl_executor.h b/gsmartcontrol/src/applib/smartctl_executor.h index 5f10c24..34d73d2 100644 --- a/gsmartcontrol/src/applib/smartctl_executor.h +++ b/gsmartcontrol/src/applib/smartctl_executor.h @@ -139,8 +139,12 @@ class SmartctlExecutorGeneric : public ExecutorSync { if (error_type == "exit") { int exit_code = 0; e->get_code(exit_code); - // ignore everyone except these - if ( !((exit_code & exit_cant_parse) || (exit_code & exit_open_failed)) ) + // Ignore everyone except this. + // Note that we don't treat exit_open_failed as failure because: + // * It may be returned from a DVD that returns product info but has no disk inside; + // * It may be returned from a usb flash drive with -d scsi; + // * exit_cant_parse is returned when opening unsupported usb drives without -d scsi. + if ( !(exit_code & exit_cant_parse) ) return; // ignore giochannel errors - higher level errors will be triggered, and they more user-friendly. diff --git a/gsmartcontrol/src/applib/smartctl_parser.cpp b/gsmartcontrol/src/applib/smartctl_parser.cpp index 949a83b..c5395d1 100644 --- a/gsmartcontrol/src/applib/smartctl_parser.cpp +++ b/gsmartcontrol/src/applib/smartctl_parser.cpp @@ -412,11 +412,26 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p) p.value_type = StorageProperty::value_type_string; p.value_string = p.reported_value; - } else if (app_pcre_match("/^Device Model$/mi", p.reported_name)) { + } else if (app_pcre_match("/^(?:Device Model|Device|Product)$/mi", p.reported_name)) { // "Device" and "Product" are from scsi/usb p.set_name(p.reported_name, "device_model", "Device Model"); p.value_type = StorageProperty::value_type_string; p.value_string = p.reported_value; + } else if (app_pcre_match("/^Vendor$/mi", p.reported_name)) { // From scsi/usb + p.set_name(p.reported_name, "vendor", "Vendor"); + p.value_type = StorageProperty::value_type_string; + p.value_string = p.reported_value; + + } else if (app_pcre_match("/^Revision$/mi", p.reported_name)) { // From scsi/usb + p.set_name(p.reported_name, "revision", "Revision"); + p.value_type = StorageProperty::value_type_string; + p.value_string = p.reported_value; + + } else if (app_pcre_match("/^Device type$/mi", p.reported_name)) { // From scsi/usb + p.set_name(p.reported_name, "device_type", "Device Type"); + p.value_type = StorageProperty::value_type_string; + p.value_string = p.reported_value; + } else if (app_pcre_match("/^Serial Number$/mi", p.reported_name)) { p.set_name(p.reported_name, "serial_number", "Serial Number"); p.value_type = StorageProperty::value_type_string; @@ -452,6 +467,11 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p) p.value_type = StorageProperty::value_type_string; // prints a single value (if it's not 512) p.value_string = p.reported_value; + } else if (app_pcre_match("/^Logical block size$/mi", p.reported_name)) { // from scsi/usb + p.set_name(p.reported_name, "logical_block_size", "Logical Block Size"); + p.value_type = StorageProperty::value_type_string; // "512 bytes" + p.value_string = p.reported_value; + } else if (app_pcre_match("/^Rotation Rate$/mi", p.reported_name)) { p.set_name(p.reported_name, "rotation_rate", "Rotation Rate"); p.value_type = StorageProperty::value_type_string; @@ -514,6 +534,9 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p) p.value_bool = true; // let's be optimistic - just hope that it doesn't hurt. } + } else if (app_pcre_match("/^scsiMode/mi", p.reported_name)) { // these are some debug warnings from smartctl on usb flash drives + p.show_in_ui = false; + } else { debug_out_warn("app", DBG_FUNC_MSG << "Unknown property \"" << p.reported_name << "\"\n"); // this is not an error, just unknown attribute. treat it as string. diff --git a/gsmartcontrol/src/applib/storage_detector_win32.cpp b/gsmartcontrol/src/applib/storage_detector_win32.cpp index da76330..28a57d5 100644 --- a/gsmartcontrol/src/applib/storage_detector_win32.cpp +++ b/gsmartcontrol/src/applib/storage_detector_win32.cpp @@ -116,7 +116,7 @@ std::string get_scan_open_multiport_devices(std::vector& dr smartctl_def_options + "--scan-open"); if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) { - debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n"); + debug_out_warn("app", DBG_FUNC_MSG << "Smartctl binary did not execute cleanly.\n"); return smartctl_ex->get_error_msg(); } diff --git a/gsmartcontrol/src/applib/storage_device.cpp b/gsmartcontrol/src/applib/storage_device.cpp index 119280d..9138a85 100644 --- a/gsmartcontrol/src/applib/storage_device.cpp +++ b/gsmartcontrol/src/applib/storage_device.cpp @@ -64,7 +64,7 @@ StorageDevice::StorageDevice(const string& dev_or_vfile, bool is_virtual) // force_type_ = false; is_virtual_ = is_virtual; is_manually_added_ = false; - fully_parsed_ = false; + parse_status_ = parse_status_none; test_is_active_ = false; if (is_virtual) { @@ -82,7 +82,7 @@ StorageDevice::StorageDevice(const string& dev, const string& type_arg) // force_type_ = false; is_virtual_ = false; is_manually_added_ = false; - fully_parsed_ = false; + parse_status_ = parse_status_none; test_is_active_ = false; device_ = dev; @@ -112,7 +112,7 @@ StorageDevice& StorageDevice::operator=(const StorageDevice& other) virtual_file_ = other.virtual_file_; is_manually_added_ = other.is_manually_added_; - fully_parsed_ = other.fully_parsed_; + parse_status_ = other.parse_status_; test_is_active_ = other.test_is_active_; detected_type_ = other.detected_type_; @@ -137,7 +137,7 @@ void StorageDevice::clear_fetched(bool including_outputs) { full_output_.clear(); } - fully_parsed_ = false; + parse_status_ = parse_status_none; test_is_active_ = false; // not sure smart_supported_.reset(); @@ -288,6 +288,8 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si } } + set_parse_status(parse_status_info); + if (emit_signal) signal_changed.emit(this); // notify listeners @@ -350,13 +352,15 @@ std::string StorageDevice::parse_data() // but this one sets the StorageDevice class members, not properties. this->parse_basic_data(false, false); // don't emit signal, we're not complete yet. + // Call this after parse_basic_data(), since it sets parse status to "info". + this->set_parse_status(StorageDevice::parse_status_full); + // set the full properties - this->set_fully_parsed(true); this->set_properties(ps.get_properties()); // copy to our drive, overwriting old data signal_changed.emit(this); // notify listeners - return ""; + return std::string(); } // Don't show any GUI warnings on parse failure - it may just be an unsupported @@ -364,22 +368,20 @@ std::string StorageDevice::parse_data() // parsed again in Info window, and we show the warnings there. debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse smartctl output.\n"); - this->set_fully_parsed(false); - // proper parsing failed. try to at least extract info section this->info_output_ = this->full_output_; // complete output here. sometimes it's only the info section if (!this->parse_basic_data(true).empty()) { // will add some properties too. this will emit signal_changed. return ps.get_error_msg(); // return full parser's error messages - they are more detailed. } - return ""; // return ok if at least the info was ok. + return std::string(); // return ok if at least the info was ok. } -bool StorageDevice::get_fully_parsed() const +StorageDevice::parse_status_t StorageDevice::get_parse_status() const { - return fully_parsed_; + return parse_status_; } @@ -825,7 +827,7 @@ std::string StorageDevice::execute_device_smartctl(const std::string& command_op command_options, smartctl_ex, smartctl_output); if (!error_msg.empty()) { - debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n"); + debug_out_warn("app", DBG_FUNC_MSG << "Smartctl binary did not execute cleanly.\n"); // Smartctl 5.39 cvs/svn version defaults to usb type on at least linux and windows. // This means that the old SCSI identify command isn't executed by default, @@ -844,9 +846,9 @@ std::string StorageDevice::execute_device_smartctl(const std::string& command_op -void StorageDevice::set_fully_parsed(bool b) +void StorageDevice::set_parse_status(parse_status_t value) { - fully_parsed_ = b; + parse_status_ = value; } diff --git a/gsmartcontrol/src/applib/storage_device.h b/gsmartcontrol/src/applib/storage_device.h index 6246467..2b24d4e 100644 --- a/gsmartcontrol/src/applib/storage_device.h +++ b/gsmartcontrol/src/applib/storage_device.h @@ -67,6 +67,14 @@ class StorageDevice : public hz::intrusive_ptr_referenced { static bool order_less_than(const StorageDeviceRefPtr& a, const StorageDeviceRefPtr& b); + /// Statuses of various parse states + enum parse_status_t { + parse_status_full, ///< Fully parsed + parse_status_info, ///< Only info section available + parse_status_none, ///< No data + }; + + /// Constructor StorageDevice(const std::string& dev_or_vfile, bool is_virtual = false); @@ -100,7 +108,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { std::string parse_data(); /// Get the "fully parsed" flag - bool get_fully_parsed() const; + parse_status_t get_parse_status() const; /// Try to enable SMART. @@ -239,7 +247,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { protected: /// Set the "fully parsed" flag - void set_fully_parsed(bool b); + void set_parse_status(parse_status_t value); /// Set parsed properties void set_properties(const SmartctlParser::prop_list_t& props); @@ -258,7 +266,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { std::string virtual_file_; ///< A file (smartctl data) the virtual device was loaded from bool is_manually_added_; ///< StorageDevice doesn't use it, but it's useful for its users. - bool fully_parsed_; ///< "Fully parsed" flag + parse_status_t parse_status_; ///< "Fully parsed" flag /// Sort of a "lock". If true, the device is not allowed to perform any commands /// except "-l selftest" and maybe "--capabilities" and "--info" (not sure). diff --git a/gsmartcontrol/src/applib/storage_property.h b/gsmartcontrol/src/applib/storage_property.h index ff9a70f..dc9d1b5 100644 --- a/gsmartcontrol/src/applib/storage_property.h +++ b/gsmartcontrol/src/applib/storage_property.h @@ -354,7 +354,7 @@ class StorageProperty { /// Constructor StorageProperty() : section(section_unknown), subsection(subsection_unknown), - value_type(value_type_unknown), warning(warning_none) + value_type(value_type_unknown), warning(warning_none), show_in_ui(true) { // value_from_db = false; value_integer = 0; // this should nullify all union members @@ -435,6 +435,8 @@ class StorageProperty { warning_t warning; ///< Warning severity for this property std::string warning_reason; // Warning reason (displayable) + bool show_in_ui; ///< Whether to show this property in UI or not + }; diff --git a/gsmartcontrol/src/gsc_info_window.cpp b/gsmartcontrol/src/gsc_info_window.cpp index 994f723..e1212d3 100644 --- a/gsmartcontrol/src/gsc_info_window.cpp +++ b/gsmartcontrol/src/gsc_info_window.cpp @@ -408,6 +408,10 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests int row = 1; // row 0 is always empty. this way it's much easier. for (prop_iterator iter = id_props.begin(); iter != id_props.end(); ++iter) { + if (!iter->show_in_ui) { + continue; // hide debug messages from smartctl + } + if (iter->generic_name == "overall_health") // a little distance for this one ++row; @@ -1302,7 +1306,12 @@ void GscInfoWindow::on_view_output_button_clicked() GscTextWindow* win = GscTextWindow::create(); // make save visible and enable monospace font - win->set_text("Smartctl Output", this->drive->get_full_output(), true, true); + std::string output = this->drive->get_full_output(); + if (output.empty()) { + output = this->drive->get_info_output(); + } + + win->set_text("Smartctl Output", output, true, true); std::string filename = drive->get_save_filename(); if (!filename.empty()) diff --git a/gsmartcontrol/src/gsc_main_window.cpp b/gsmartcontrol/src/gsc_main_window.cpp index 06b70c2..25da121 100644 --- a/gsmartcontrol/src/gsc_main_window.cpp +++ b/gsmartcontrol/src/gsc_main_window.cpp @@ -1189,8 +1189,8 @@ GscInfoWindow* GscMainWindow::show_device_info_window(StorageDeviceRefPtr drive) // Virtual drives are parsed at load time. - // Parse non-virtual drives here. - if (!drive->get_is_virtual()) { + // Parse non-virtual, smart-supporting drives here. + if (!drive->get_is_virtual() && drive->get_smart_status() != StorageDevice::status_unsupported) { SmartctlExecutorGuiRefPtr ex(new SmartctlExecutorGui()); ex->create_running_dialog(this, "Running %s on " + drive->get_device_with_type() + "..."); std::string error_msg = drive->fetch_data_and_parse(ex); // run it with GUI support @@ -1205,7 +1205,7 @@ GscInfoWindow* GscMainWindow::show_device_info_window(StorageDeviceRefPtr drive) // If the drive output wasn't fully parsed (happens with e.g. scsi and // usb devices), only very basic info is available and there's no point // in showing this window. - for both virtual and non-virtual. - if (!drive->get_fully_parsed()) { + if (drive->get_parse_status() == StorageDevice::parse_status_none) { gsc_no_info_dialog_show("No additional information is available for this drive.", "", this, false, drive->get_info_output(), "Smartctl Output", drive->get_save_filename()); return 0; diff --git a/gsmartcontrol/src/hz/sync_policy_glib.h b/gsmartcontrol/src/hz/sync_policy_glib.h index bb622cd..21d00d5 100644 --- a/gsmartcontrol/src/hz/sync_policy_glib.h +++ b/gsmartcontrol/src/hz/sync_policy_glib.h @@ -20,128 +20,243 @@ Glib-based policy. */ -/// Lock GStaticMutex -#define hz_glib_static_mutex_lock(mutex) \ - g_mutex_lock(g_static_mutex_get_mutex(mutex)) - -/// Try locking GStaticMutex -#define hz_glib_static_mutex_trylock(mutex) \ - g_mutex_trylock(g_static_mutex_get_mutex(mutex)) - -/// Unlock GStaticMutex -#define hz_glib_static_mutex_unlock(mutex) \ - g_mutex_unlock(g_static_mutex_get_mutex(mutex)) - - - - namespace hz { -/// C++ Wrapper for Glib mutex -class MutexGlib : public hz::noncopyable { - public: - typedef GStaticMutex native_type; - - static void native_lock(native_type& mutex) - { - hz_glib_static_mutex_lock(&mutex); - } - - static bool native_trylock(native_type& mutex) - { - return hz_glib_static_mutex_trylock(&mutex); - } - - static void native_unlock(native_type& mutex) - { - hz_glib_static_mutex_unlock(&mutex); - } - - MutexGlib() { g_static_mutex_init(&mutex_); } - ~MutexGlib() { g_static_mutex_free(&mutex_); } - - void lock() { native_lock(mutex_); } - bool trylock() { return native_trylock(mutex_); } - void unlock() { native_unlock(mutex_); } - - private: - GStaticMutex mutex_; // use StaticMutex, I think it uses less heap memory -}; +#if GLIB_CHECK_VERSION(2, 32, 0) + /// C++ Wrapper for Glib mutex + class MutexGlib : public hz::noncopyable { + public: + typedef GMutex native_type; -/// C++ Wrapper for Glib recursive mutex -class RecMutexGlib : public hz::noncopyable { - public: - typedef GStaticRecMutex native_type; - - static void native_lock(native_type& mutex) - { - g_static_rec_mutex_lock(&mutex); - } - - static bool native_trylock(native_type& mutex) - { - return g_static_rec_mutex_trylock(&mutex); - } - - static void native_unlock(native_type& mutex) - { - g_static_rec_mutex_unlock(&mutex); - } - - RecMutexGlib() { g_static_rec_mutex_init(&mutex_); } - ~RecMutexGlib() { g_static_rec_mutex_free(&mutex_); } - - void lock() { native_lock(mutex_); } - bool trylock() { return native_trylock(mutex_); } - void unlock() { native_unlock(mutex_); } - - private: - GStaticRecMutex mutex_; -}; - - - -/// C++ Wrapper for Glib RW lock -class RWMutexGlib : public hz::noncopyable { - public: - typedef GStaticRWLock native_type; - - static void native_lock(native_type& mutex, bool for_write = false) - { - if (for_write) { - g_static_rw_lock_writer_lock(&mutex); - } else { - g_static_rw_lock_reader_lock(&mutex); + static void native_lock(native_type& mutex) + { + g_mutex_lock(&mutex); } - } - static bool native_trylock(native_type& mutex, bool for_write = false) - { - return (for_write ? g_static_rw_lock_writer_trylock(&mutex) : g_static_rw_lock_reader_trylock(&mutex)); - } - - static void native_unlock(native_type& mutex, bool for_write = false) - { - if (for_write) { - g_static_rw_lock_writer_unlock(&mutex); - } else { - g_static_rw_lock_reader_unlock(&mutex); + static bool native_trylock(native_type& mutex) + { + return g_mutex_trylock(&mutex); } - } - RWMutexGlib() { g_static_rw_lock_init(&mutex_); } - ~RWMutexGlib() { g_static_rw_lock_free(&mutex_); } + static void native_unlock(native_type& mutex) + { + g_mutex_unlock(&mutex); + } - void lock(bool for_write = false) { native_lock(mutex_, for_write); } - bool trylock(bool for_write = false) { return native_trylock(mutex_, for_write); } - void unlock(bool for_write = false) { native_unlock(mutex_, for_write); } + MutexGlib() { g_mutex_init(&mutex_); } + ~MutexGlib() { g_mutex_clear(&mutex_); } - private: - GStaticRWLock mutex_; -}; + void lock() { native_lock(mutex_); } + bool trylock() { return native_trylock(mutex_); } + void unlock() { native_unlock(mutex_); } + + private: + GMutex mutex_; + }; + + + + /// C++ Wrapper for Glib recursive mutex + class RecMutexGlib : public hz::noncopyable { + public: + typedef GRecMutex native_type; + + static void native_lock(native_type& mutex) + { + g_rec_mutex_lock(&mutex); + } + + static bool native_trylock(native_type& mutex) + { + return g_rec_mutex_trylock(&mutex); + } + + static void native_unlock(native_type& mutex) + { + g_rec_mutex_unlock(&mutex); + } + + RecMutexGlib() { g_rec_mutex_init(&mutex_); } + ~RecMutexGlib() { g_rec_mutex_clear(&mutex_); } + + void lock() { native_lock(mutex_); } + bool trylock() { return native_trylock(mutex_); } + void unlock() { native_unlock(mutex_); } + + private: + GRecMutex mutex_; + }; + + + + /// C++ Wrapper for Glib RW lock + class RWMutexGlib : public hz::noncopyable { + public: + typedef GRWLock native_type; + + static void native_lock(native_type& mutex, bool for_write = false) + { + if (for_write) { + g_rw_lock_writer_lock(&mutex); + } else { + g_rw_lock_reader_lock(&mutex); + } + } + + static bool native_trylock(native_type& mutex, bool for_write = false) + { + return (for_write ? g_rw_lock_writer_trylock(&mutex) : g_rw_lock_reader_trylock(&mutex)); + } + + static void native_unlock(native_type& mutex, bool for_write = false) + { + if (for_write) { + g_rw_lock_writer_unlock(&mutex); + } else { + g_rw_lock_reader_unlock(&mutex); + } + } + + RWMutexGlib() { g_rw_lock_init(&mutex_); } + ~RWMutexGlib() { g_rw_lock_clear(&mutex_); } + + void lock(bool for_write = false) { native_lock(mutex_, for_write); } + bool trylock(bool for_write = false) { return native_trylock(mutex_, for_write); } + void unlock(bool for_write = false) { native_unlock(mutex_, for_write); } + + private: + GRWLock mutex_; + }; + + + +#else // older glib + + + /// Lock GStaticMutex + #define hz_glib_static_mutex_lock(mutex) \ + g_mutex_lock(g_static_mutex_get_mutex(mutex)) + + /// Try locking GStaticMutex + #define hz_glib_static_mutex_trylock(mutex) \ + g_mutex_trylock(g_static_mutex_get_mutex(mutex)) + + /// Unlock GStaticMutex + #define hz_glib_static_mutex_unlock(mutex) \ + g_mutex_unlock(g_static_mutex_get_mutex(mutex)) + + + + /// C++ Wrapper for Glib mutex + class MutexGlib : public hz::noncopyable { + public: + typedef GStaticMutex native_type; + + static void native_lock(native_type& mutex) + { + hz_glib_static_mutex_lock(&mutex); + } + + static bool native_trylock(native_type& mutex) + { + return hz_glib_static_mutex_trylock(&mutex); + } + + static void native_unlock(native_type& mutex) + { + hz_glib_static_mutex_unlock(&mutex); + } + + MutexGlib() { g_static_mutex_init(&mutex_); } + ~MutexGlib() { g_static_mutex_free(&mutex_); } + + void lock() { native_lock(mutex_); } + bool trylock() { return native_trylock(mutex_); } + void unlock() { native_unlock(mutex_); } + + private: + GStaticMutex mutex_; // use StaticMutex, I think it uses less heap memory + }; + + + + /// C++ Wrapper for Glib recursive mutex + class RecMutexGlib : public hz::noncopyable { + public: + typedef GStaticRecMutex native_type; + + static void native_lock(native_type& mutex) + { + g_static_rec_mutex_lock(&mutex); + } + + static bool native_trylock(native_type& mutex) + { + return g_static_rec_mutex_trylock(&mutex); + } + + static void native_unlock(native_type& mutex) + { + g_static_rec_mutex_unlock(&mutex); + } + + RecMutexGlib() { g_static_rec_mutex_init(&mutex_); } + ~RecMutexGlib() { g_static_rec_mutex_free(&mutex_); } + + void lock() { native_lock(mutex_); } + bool trylock() { return native_trylock(mutex_); } + void unlock() { native_unlock(mutex_); } + + private: + GStaticRecMutex mutex_; + }; + + + + /// C++ Wrapper for Glib RW lock + class RWMutexGlib : public hz::noncopyable { + public: + typedef GStaticRWLock native_type; + + static void native_lock(native_type& mutex, bool for_write = false) + { + if (for_write) { + g_static_rw_lock_writer_lock(&mutex); + } else { + g_static_rw_lock_reader_lock(&mutex); + } + } + + static bool native_trylock(native_type& mutex, bool for_write = false) + { + return (for_write ? g_static_rw_lock_writer_trylock(&mutex) : g_static_rw_lock_reader_trylock(&mutex)); + } + + static void native_unlock(native_type& mutex, bool for_write = false) + { + if (for_write) { + g_static_rw_lock_writer_unlock(&mutex); + } else { + g_static_rw_lock_reader_unlock(&mutex); + } + } + + RWMutexGlib() { g_static_rw_lock_init(&mutex_); } + ~RWMutexGlib() { g_static_rw_lock_free(&mutex_); } + + void lock(bool for_write = false) { native_lock(mutex_, for_write); } + bool trylock(bool for_write = false) { return native_trylock(mutex_, for_write); } + void unlock(bool for_write = false) { native_unlock(mutex_, for_write); } + + private: + GStaticRWLock mutex_; + }; + + +#endif @@ -198,7 +313,12 @@ struct SyncPolicyGlib : public SyncScopedLockProvider { // Static methods /// If glib threads are unavailable, this will abort. + +#if GLIB_CHECK_VERSION(2, 32, 0) + static bool init() { return true; } // g_thread_init() does nothing and is deprecated since 2.32. +#else static bool init() { if (!g_thread_supported()) g_thread_init(NULL); return true; } +#endif static void lock(Mutex& m) { m.lock(); } static bool trylock(Mutex& m) { return m.trylock(); } diff --git a/gsmartcontrol/src/res/gsc_main_window.glade b/gsmartcontrol/src/res/gsc_main_window.glade index b8ddf63..d18bbb6 100644 --- a/gsmartcontrol/src/res/gsc_main_window.glade +++ b/gsmartcontrol/src/res/gsc_main_window.glade @@ -3,8 +3,8 @@ GSmartControl - 460 - 350 + 580 + 400 True