mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 06:15:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e848aa3fa0 | ||
|
|
9692c78944 | ||
|
|
6fba7765f7 |
@@ -115,6 +115,7 @@ bool storage_property_autoset_description(StorageProperty& p, StorageDeviceDetec
|
||||
found = auto_set(p, "ata_smart_attributes/revision", p.displayable_name.c_str());
|
||||
if (!found) {
|
||||
auto_set_ata_attribute_description(p, device_type);
|
||||
storage_property_ata_attribute_humanize_ssd_writes(p);
|
||||
found = true; // true, because auto_set_attr() may set "Unknown attribute", which is still "found".
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,6 +22,7 @@ Copyright:
|
||||
//#include "warning_colors.h"
|
||||
#include "storage_property_descr_helpers.h"
|
||||
#include "hz/string_num.h"
|
||||
#include "hz/format_unit.h" // format_size
|
||||
|
||||
|
||||
namespace {
|
||||
@@ -1364,5 +1365,104 @@ void storage_property_ata_attribute_autoset_warning(StorageProperty& p)
|
||||
|
||||
|
||||
|
||||
void storage_property_ata_attribute_humanize_ssd_writes(StorageProperty& p)
|
||||
{
|
||||
if (p.section != StoragePropertySection::AtaAttributes || !p.is_value_type<AtaStorageAttribute>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& attr = p.get_value<AtaStorageAttribute>();
|
||||
|
||||
// Skip if readable_value is already set (e.g., by parser or for GiB attributes)
|
||||
if (!p.readable_value.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Standard sector size (512 bytes)
|
||||
constexpr uint64_t bytes_per_sector = 512;
|
||||
constexpr uint64_t mib_32 = 32ULL * 1024ULL * 1024ULL;
|
||||
constexpr uint64_t gib = 1024ULL * 1024ULL * 1024ULL;
|
||||
|
||||
// Match attribute by ID and reported name to handle vendor-specific attributes
|
||||
const int32_t id = attr.id;
|
||||
const std::string& name = p.reported_name;
|
||||
std::optional<uint64_t> bytes;
|
||||
|
||||
// Write attributes - these need humanization most
|
||||
// Attribute 199: Write_Sectors_Tot_Ct (Indilinx Barefoot SSDs)
|
||||
// Total count of written sectors
|
||||
if (id == 199 && name == "Write_Sectors_Tot_Ct") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 225: Host_Writes_32MiB (Intel SSDs)
|
||||
else if (id == 225 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 241: Host_Writes_32MiB (various SSDs)
|
||||
// Raw value increased by 1 for every 32 MiB written
|
||||
else if (id == 241 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 243: Host_Writes_32MiB (SanDisk SSDs)
|
||||
else if (id == 243 && name == "Host_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 245: Flash_Writes_32MiB (Innodisk SSDs)
|
||||
else if (id == 245 && name == "Flash_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 245: TLC_Writes_32MiB (SiliconMotion SSDs)
|
||||
else if (id == 245 && name == "TLC_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 246: SLC_Writes_32MiB (SiliconMotion SSDs)
|
||||
else if (id == 246 && name == "SLC_Writes_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 246: Total_Host_Sector_Write (Crucial/Micron SSDs)
|
||||
// Total number of sectors written by the host system
|
||||
else if (id == 246 && name == "Total_Host_Sector_Write") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 249: NAND_Writes_1GiB (Intel SSDs)
|
||||
// Note: The raw value is the count, not already in GiB
|
||||
else if (id == 249 && name == "NAND_Writes_1GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
// Attribute 249: Total_NAND_Prog_Ct_GiB (OCZ SSDs)
|
||||
else if (id == 249 && name == "Total_NAND_Prog_Ct_GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
|
||||
// Read attributes - also humanize for consistency
|
||||
// Attribute 198: Read_Sectors_Tot_Ct (Indilinx Barefoot SSDs)
|
||||
else if (id == 198 && name == "Read_Sectors_Tot_Ct") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * bytes_per_sector;
|
||||
}
|
||||
// Attribute 226: Host_Reads_32MiB (Intel SSDs)
|
||||
else if (id == 226 && name == "Host_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 242: Host_Reads_32MiB (Intel SSDs)
|
||||
else if (id == 242 && name == "Host_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 244: Flash_Reads_32MiB (Innodisk SSDs)
|
||||
else if (id == 244 && name == "Flash_Reads_32MiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * mib_32;
|
||||
}
|
||||
// Attribute 251: Total_NAND_Read_Ct_GiB (OCZ SSDs)
|
||||
else if (id == 251 && name == "Total_NAND_Read_Ct_GiB") {
|
||||
bytes = static_cast<uint64_t>(attr.raw_value_int) * gib;
|
||||
}
|
||||
|
||||
// Set readable_value if we determined the byte count
|
||||
if (bytes.has_value() && bytes.value() > 0) {
|
||||
// Use binary units (KiB, MiB, GiB, TiB) for consistency with existing attributes
|
||||
p.readable_value = hz::format_size(bytes.value(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -26,6 +26,11 @@ void auto_set_ata_attribute_description(StorageProperty& p, StorageDeviceDetecte
|
||||
void storage_property_ata_attribute_autoset_warning(StorageProperty& p);
|
||||
|
||||
|
||||
/// Humanize SSD write statistics by converting raw values to readable byte counts.
|
||||
/// Sets the readable_value field for applicable write-related attributes.
|
||||
void storage_property_ata_attribute_humanize_ssd_writes(StorageProperty& p);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -805,94 +805,6 @@ bool GscInfoWindow::on_delete_event([[maybe_unused]] GdkEventAny* e)
|
||||
|
||||
|
||||
|
||||
bool GscInfoWindow::on_key_press_event(GdkEventKey* event)
|
||||
{
|
||||
// Handle Ctrl+Tab and Ctrl+Shift+Tab for tab navigation
|
||||
if ( (event->state & GDK_CONTROL_MASK)
|
||||
&& (event->keyval == GDK_KEY_Tab || event->keyval == GDK_KEY_ISO_Left_Tab)) {
|
||||
|
||||
// Helper to cycle only across visible notebook pages
|
||||
auto cycle_visible_pages = [&](Gtk::Notebook* notebook) -> bool {
|
||||
if (!notebook) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int n_pages = notebook->get_n_pages();
|
||||
std::vector<int> visible_pages;
|
||||
visible_pages.reserve(n_pages);
|
||||
|
||||
for (int i = 0; i < n_pages; ++i) {
|
||||
if (auto* page = notebook->get_nth_page(i)) {
|
||||
if (page->get_visible()) {
|
||||
visible_pages.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need at least two visible pages to make cycling meaningful
|
||||
if (visible_pages.size() <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int current_page = notebook->get_current_page();
|
||||
int visible_index = 0;
|
||||
|
||||
auto it = std::find(visible_pages.begin(), visible_pages.end(), current_page);
|
||||
if (it != visible_pages.end()) {
|
||||
visible_index = static_cast<int>(std::distance(visible_pages.begin(), it));
|
||||
}
|
||||
|
||||
int next_visible_index = 0;
|
||||
|
||||
// Check if Shift is also pressed for backward navigation
|
||||
if (event->state & GDK_SHIFT_MASK) {
|
||||
// Ctrl+Shift+Tab: go to previous visible tab
|
||||
next_visible_index =
|
||||
(visible_index - 1 + static_cast<int>(visible_pages.size())) %
|
||||
static_cast<int>(visible_pages.size());
|
||||
} else {
|
||||
// Ctrl+Tab: go to next visible tab
|
||||
next_visible_index =
|
||||
(visible_index + 1) %
|
||||
static_cast<int>(visible_pages.size());
|
||||
}
|
||||
|
||||
notebook->set_current_page(visible_pages[next_visible_index]);
|
||||
return true;
|
||||
};
|
||||
|
||||
auto* main_notebook = lookup_widget<Gtk::Notebook*>("main_notebook");
|
||||
if (main_notebook) {
|
||||
// Check if we're on the Advanced tab with sub-tabs
|
||||
auto* advanced_tab_vbox = lookup_widget<Gtk::Box*>("advanced_tab_vbox");
|
||||
auto* advanced_notebook = lookup_widget<Gtk::Notebook*>("advanced_notebook");
|
||||
|
||||
// Only handle sub-tab cycling if the Advanced tab is currently active
|
||||
if (advanced_tab_vbox && advanced_notebook && advanced_notebook->get_visible()) {
|
||||
const int advanced_page_num = main_notebook->page_num(*advanced_tab_vbox);
|
||||
const int current_main_page = main_notebook->get_current_page();
|
||||
|
||||
// Advanced tab is active, so cycle through its sub-tabs
|
||||
if (advanced_page_num >= 0 && advanced_page_num == current_main_page) {
|
||||
if (cycle_visible_pages(advanced_notebook)) {
|
||||
return true; // event handled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, cycle through main notebook tabs
|
||||
if (cycle_visible_pages(main_notebook)) {
|
||||
return true; // event handled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call base class handler for other keys
|
||||
return Gtk::Window::on_key_press_event(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GscInfoWindow::on_refresh_info_button_clicked()
|
||||
{
|
||||
this->refresh_info();
|
||||
|
||||
@@ -217,10 +217,6 @@ class GscInfoWindow : public AppBuilderWidget<GscInfoWindow, true> {
|
||||
/// Reimplemented from Gtk::Window.
|
||||
bool on_delete_event(GdkEventAny* e) override;
|
||||
|
||||
/// Handle key press events for keyboard navigation.
|
||||
/// Reimplemented from Gtk::Window.
|
||||
bool on_key_press_event(GdkEventKey* event) override;
|
||||
|
||||
|
||||
// ---------- Other callbacks
|
||||
|
||||
|
||||
Reference in New Issue
Block a user