diff --git a/src/config.c b/src/config.c index acfbec758..95362bc06 100644 --- a/src/config.c +++ b/src/config.c @@ -1517,6 +1517,9 @@ load_other_removable_devices(void) sprintf(temp, "zip_%02i_image_path", c + 1); p = ini_section_get_string(cat, temp, ""); + + sprintf(temp, "zip_%02i_writeprot", c + 1); + zip_drives[c].read_only = ini_section_get_int(cat, temp, 0); if (!strcmp(p, usr_path)) p[0] = 0x00; @@ -1630,6 +1633,9 @@ load_other_removable_devices(void) sprintf(temp, "mo_%02i_image_path", c + 1); p = ini_section_get_string(cat, temp, ""); + sprintf(temp, "mo_%02i_writeprot", c + 1); + mo_drives[c].read_only = ini_section_get_int(cat, temp, 0); + if (!strcmp(p, usr_path)) p[0] = 0x00; @@ -3090,6 +3096,12 @@ save_other_removable_devices(void) sprintf(temp, "zip_%02i_scsi_id", c + 1); ini_section_delete_var(cat, temp); + sprintf(temp, "zip_%02i_writeprot", c + 1); + if (zip_drives[c].read_only) + ini_section_set_int(cat, temp, zip_drives[c].read_only); + else + ini_section_delete_var(cat, temp); + sprintf(temp, "zip_%02i_scsi_location", c + 1); if (zip_drives[c].bus_type != ZIP_BUS_SCSI) ini_section_delete_var(cat, temp); @@ -3146,6 +3158,12 @@ save_other_removable_devices(void) sprintf(temp, "mo_%02i_scsi_id", c + 1); ini_section_delete_var(cat, temp); + sprintf(temp, "mo_%02i_writeprot", c + 1); + if (mo_drives[c].read_only) + ini_section_set_int(cat, temp, mo_drives[c].read_only); + else + ini_section_delete_var(cat, temp); + sprintf(temp, "mo_%02i_scsi_location", c + 1); if (mo_drives[c].bus_type != MO_BUS_SCSI) ini_section_delete_var(cat, temp); diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 1623f932a..b5eb8c8fc 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -483,6 +483,7 @@ fdd_load(int drive, char *fn) drive_empty[drive] = 0; fdd_forced_seek(drive, 0); fdd_changed[drive] = 1; + ui_sb_update_icon_wp(SB_FLOPPY | drive, ui_writeprot[drive]); return; } c++; diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index e6e9e6acd..66805e653 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -5,6 +5,7 @@ typedef struct dev_status_empty_active_t { atomic_bool_t empty; atomic_bool_t active; atomic_bool_t write_active; + atomic_bool_t write_prot; } dev_status_empty_active_t; typedef struct dev_status_active_t { diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 783400ebc..f4efd6ec1 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -67,6 +67,7 @@ extern void ui_sb_update_tip(int meaning); extern void ui_sb_update_icon(int tag, int active); extern void ui_sb_update_icon_write(int tag, int write); extern void ui_sb_update_icon_state(int tag, int state); +extern void ui_sb_update_icon_wp(int tag, int state); extern void ui_sb_set_text_w(wchar_t *wstr); extern void ui_sb_set_text(char *str); extern void ui_sb_bugui(char *str); diff --git a/src/qt/icons/write_protected.ico b/src/qt/icons/write_protected.ico new file mode 100644 index 000000000..f867ab373 Binary files /dev/null and b/src/qt/icons/write_protected.ico differ diff --git a/src/qt/qt_iconindicators.cpp b/src/qt/qt_iconindicators.cpp index d5d22c78d..8440af7dc 100644 --- a/src/qt/qt_iconindicators.cpp +++ b/src/qt/qt_iconindicators.cpp @@ -12,6 +12,8 @@ getIndicatorIcon(IconIndicator indicator) return QIcon(":/settings/qt/icons/write_active.ico"); case Disabled: return QIcon(":/settings/qt/icons/disabled.ico"); + case WriteProtected: + return QIcon(":/settings/qt/icons/write_protected.ico"); default: return QIcon(); } @@ -26,11 +28,11 @@ getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, return iconPixmap; auto painter = QPainter(&iconPixmap); - auto indicatorPixmap = getIndicatorIcon(indicator == ReadWriteActive ? Active : indicator).pixmap(size); + auto indicatorPixmap = getIndicatorIcon((indicator == ReadWriteActive || indicator == WriteProtectedActive) ? Active : indicator).pixmap(size); painter.drawPixmap(0, 0, indicatorPixmap); - if (indicator == ReadWriteActive) { - auto writeIndicatorPixmap = getIndicatorIcon(WriteActive).pixmap(size); + if (indicator == ReadWriteActive || indicator == WriteProtectedActive) { + auto writeIndicatorPixmap = getIndicatorIcon(indicator == WriteProtectedActive ? WriteProtected : WriteActive).pixmap(size); painter.drawPixmap(0, 0, writeIndicatorPixmap); } painter.end(); diff --git a/src/qt/qt_iconindicators.hpp b/src/qt/qt_iconindicators.hpp index 12f82f259..d2232fc77 100644 --- a/src/qt/qt_iconindicators.hpp +++ b/src/qt/qt_iconindicators.hpp @@ -10,6 +10,8 @@ enum IconIndicator { WriteActive, ReadWriteActive, Disabled, + WriteProtected, + WriteProtectedActive, }; QPixmap getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator); diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index db32569f3..5a731c188 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -91,6 +91,8 @@ struct PixmapSetEmptyActive { QPixmap read_write_active; QPixmap empty_write_active; QPixmap empty_read_write_active; + QPixmap wp; + QPixmap wp_active; void load(const QIcon &icon); }; struct Pixmaps { @@ -168,6 +170,7 @@ struct StateEmptyActive { bool empty = false; bool active = false; bool write_active = false; + bool wp = false; void setActive(bool b) { @@ -193,6 +196,14 @@ struct StateEmptyActive { empty = b; refresh(); } + void setWriteProtected(bool b) + { + if (!label || b == wp) + return; + + wp = b; + refresh(); + } void refresh() { if (!label) @@ -203,7 +214,9 @@ struct StateEmptyActive { else label->setPixmap(write_active ? pixmaps->empty_write_active : (active ? pixmaps->empty_active : pixmaps->empty)); } else { - if (active && write_active) + if (wp) + label->setPixmap(active ? pixmaps->wp_active : pixmaps->wp); + else if (active && write_active) label->setPixmap(pixmaps->read_write_active); else label->setPixmap(write_active ? pixmaps->write_active : (active ? pixmaps->active : pixmaps->normal)); @@ -241,6 +254,8 @@ void PixmapSetEmptyActive::load(const QIcon &icon) { normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + wp = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteProtected); + wp_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteProtectedActive); active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteActive); read_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, ReadWriteActive); @@ -454,16 +469,23 @@ MachineStatus::refreshEmptyIcons() if (!sbar_initialized) return; - for (size_t i = 0; i < FDD_NUM; ++i) + for (size_t i = 0; i < FDD_NUM; ++i) { d->fdd[i].setEmpty(machine_status.fdd[i].empty); + d->fdd[i].setWriteProtected(machine_status.fdd[i].write_prot); + } for (size_t i = 0; i < CDROM_NUM; ++i) d->cdrom[i].setEmpty(machine_status.cdrom[i].empty); - for (size_t i = 0; i < ZIP_NUM; i++) + for (size_t i = 0; i < ZIP_NUM; i++) { d->zip[i].setEmpty(machine_status.zip[i].empty); - for (size_t i = 0; i < MO_NUM; i++) + d->zip[i].setWriteProtected(machine_status.zip[i].write_prot); + } + for (size_t i = 0; i < MO_NUM; i++) { d->mo[i].setEmpty(machine_status.mo[i].empty); + d->mo[i].setWriteProtected(machine_status.mo[i].write_prot); + } d->cassette.setEmpty(machine_status.cassette.empty); + d->cassette.setWriteProtected(machine_status.cassette.write_prot); for (size_t i = 0; i < NET_CARD_MAX; i++) d->net[i].setEmpty(machine_status.net[i].empty); @@ -595,6 +617,7 @@ MachineStatus::refresh(QStatusBar *sbar) if (cassette_enable) { d->cassette.label = std::make_unique(); d->cassette.setEmpty(QString(cassette_fname).isEmpty()); + d->cassette.setWriteProtected(cassette_ui_writeprot); d->cassette.refresh(); connect((ClickableLabel *) d->cassette.label.get(), &ClickableLabel::clicked, [](QPoint pos) { MediaMenu::ptr->cassetteMenu->popup(pos - QPoint(0, MediaMenu::ptr->cassetteMenu->sizeHint().height())); @@ -635,6 +658,7 @@ MachineStatus::refresh(QStatusBar *sbar) } d->fdd[i].label = std::make_unique(); d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty()); + d->fdd[i].setWriteProtected(ui_writeprot[i]); d->fdd[i].setActive(false); d->fdd[i].setWriteActive(false); d->fdd[i].refresh(); @@ -669,6 +693,7 @@ MachineStatus::refresh(QStatusBar *sbar) iterateZIP([this, sbar](int i) { d->zip[i].label = std::make_unique(); d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty()); + d->zip[i].setWriteProtected(zip_drives[i].read_only); d->zip[i].setActive(false); d->zip[i].setWriteActive(false); d->zip[i].refresh(); @@ -686,6 +711,7 @@ MachineStatus::refresh(QStatusBar *sbar) iterateMO([this, sbar](int i) { d->mo[i].label = std::make_unique(); d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty()); + d->mo[i].setWriteProtected(mo_drives[i].read_only); d->mo[i].setActive(false); d->mo[i].setWriteActive(false); d->mo[i].refresh(); diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 11fac2a70..c9d658fb2 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -282,6 +282,7 @@ MediaMenu::cassetteMount(const QString &filename, bool wp) } ui_sb_update_icon_state(SB_CASSETTE, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_wp(SB_CASSETTE, cassette_ui_writeprot); mhm.addImageToHistory(0, ui::MediaType::Cassette, previous_image.filePath(), filename); cassetteUpdateMenu(); ui_sb_update_tip(SB_CASSETTE); @@ -446,6 +447,7 @@ MediaMenu::floppyMount(int i, const QString &filename, bool wp) fdd_load(i, filenameBytes.data()); } ui_sb_update_icon_state(SB_FLOPPY | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_wp(SB_FLOPPY | i, ui_writeprot[i]); mhm.addImageToHistory(i, ui::MediaType::Floppy, previous_image.filePath(), filename); floppyUpdateMenu(i); ui_sb_update_tip(SB_FLOPPY | i); @@ -822,6 +824,7 @@ MediaMenu::zipMount(int i, const QString &filename, bool wp) mhm.addImageToHistory(i, ui::MediaType::Zip, zip_drives[i].prev_image_path, zip_drives[i].image_path); ui_sb_update_icon_state(SB_ZIP | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_wp(SB_ZIP | i, wp); zipUpdateMenu(i); ui_sb_update_tip(SB_ZIP | i); @@ -858,6 +861,7 @@ MediaMenu::zipReloadPrev(int i) } else { ui_sb_update_icon_state(SB_ZIP | i, 0); } + ui_sb_update_icon_wp(SB_ZIP | i, zip_drives[i].read_only); zipUpdateMenu(i); ui_sb_update_tip(SB_ZIP | i); @@ -869,7 +873,7 @@ void MediaMenu::zipReload(int index, int slot) { const QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Zip); - zipMount(index, filename, false); + zipMount(index, filename, zip_drives[index].read_only); zipUpdateMenu(index); ui_sb_update_tip(SB_ZIP | index); } @@ -995,6 +999,7 @@ MediaMenu::moReloadPrev(int i) } else { ui_sb_update_icon_state(SB_MO | i, 0); } + ui_sb_update_icon_state(SB_MO | i, mo_drives[i].read_only); moUpdateMenu(i); ui_sb_update_tip(SB_MO | i); diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 6e0b3cfbb..337b438f3 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -262,6 +262,34 @@ ui_sb_set_ready(int ready) } } +void +ui_sb_update_icon_wp(int tag, int state) +{ + const auto temp = static_cast(tag); + const int category = static_cast(temp & 0xfffffff0); + const int item = tag & 0xf; + + switch (category) { + default: + break; + case SB_CASSETTE: + machine_status.cassette.write_prot = state > 0 ? true : false; + break; + case SB_FLOPPY: + machine_status.fdd[item].write_prot = state > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].write_prot = state > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].write_prot = state > 0 ? true : false; + break; + } + + if (main_window != nullptr) + main_window->updateStatusEmptyIcons(); +} + void ui_sb_update_icon_state(int tag, int state) { diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index 51518b8f6..9291892b5 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -28,6 +28,7 @@ qt/icons/zip.ico qt/icons/zip_disabled.ico qt/icons/active.ico + qt/icons/write_protected.ico qt/icons/write_active.ico qt/icons/disabled.ico qt/icons/86Box-gray.ico diff --git a/src/unix/unix.c b/src/unix/unix.c index f3580cd19..5a69424b4 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -948,6 +948,11 @@ void (*f_rl_callback_handler_remove)(void) = NULL; # define LIBEDIT_LIBRARY "libedit.so" #endif +void ui_sb_update_icon_wp(int tag, int state) +{ + /* No-op */ +} + uint32_t timer_onesec(uint32_t interval, UNUSED(void *param)) {