Add "Eject" button to main window.

Since especially Windows puts the eject functionality behind an icon in the
systray which is usually hidden and doesn't complain if a USB drive is
unplugged without ejecting it first ejecting such a device might not be
obvious to everyone. Add a button to the main window allowing to eject the
selected player.

Currently only implemented for Windows.

Change-Id: I785ac1482cda03a1379cf6d0fd0d9a0ff8130092
This commit is contained in:
Dominik Riebeling 2012-09-08 20:34:36 +02:00
parent 4f99dd4264
commit 328ff6d979
7 changed files with 137 additions and 29 deletions

View file

@ -692,3 +692,63 @@ QStringList Utils::findRunningProcess(QStringList names)
qDebug() << "[Utils] Found listed processes running:" << found;
return found;
}
/** Eject device from PC.
* Request the OS to eject the player.
* @param device mountpoint of the device
* @return true on success, fals otherwise.
*/
bool Utils::ejectDevice(QString device)
{
#if defined(Q_OS_WIN32)
/* See http://support.microsoft.com/kb/165721 on the procedure to eject a
* device. */
bool success = false;
int i;
HANDLE hdl;
DWORD bytesReturned;
TCHAR volume[8];
/* CreateFile */
_stprintf(volume, _TEXT("\\\\.\\%c:"), device.toAscii().at(0));
hdl = CreateFile(volume, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hdl == INVALID_HANDLE_VALUE)
return false;
/* lock volume to make sure no other application is accessing the volume.
* Try up to 10 times. */
for(i = 0; i < 10; i++) {
if(DeviceIoControl(hdl, FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0, &bytesReturned, NULL))
break;
/* short break before retry */
Sleep(100);
}
if(i < 10) {
/* successfully locked, now dismount */
if(DeviceIoControl(hdl, FSCTL_DISMOUNT_VOLUME,
NULL, 0, NULL, 0, &bytesReturned, NULL)) {
/* make sure media can be removed. */
PREVENT_MEDIA_REMOVAL pmr;
pmr.PreventMediaRemoval = false;
if(DeviceIoControl(hdl, IOCTL_STORAGE_MEDIA_REMOVAL,
&pmr, sizeof(PREVENT_MEDIA_REMOVAL),
NULL, 0, &bytesReturned, NULL)) {
/* eject the media */
if(DeviceIoControl(hdl, IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0, NULL, 0, &bytesReturned, NULL))
success = true;
}
}
}
/* close handle */
CloseHandle(hdl);
return success;
#endif
return false;
}

View file

@ -50,6 +50,7 @@ public:
static QString resolveDevicename(QString path);
static QString resolveMountPoint(QString device);
static QStringList findRunningProcess(QStringList names);
static bool ejectDevice(QString device);
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View file

@ -110,6 +110,11 @@ RbUtilQt::RbUtilQt(QWidget *parent) : QMainWindow(parent)
RegCloseKey(hk);
}
#endif
#if !defined(Q_OS_WIN32)
/* eject funtionality is only implemented on W32 right now. */
ui.buttonEject->setEnabled(false);
#endif
updateDevice();
downloadInfo();
@ -142,6 +147,7 @@ RbUtilQt::RbUtilQt(QWidget *parent) : QMainWindow(parent)
connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(configDialog()));
connect(ui.actionE_xit, SIGNAL(triggered()), this, SLOT(shutdown()));
connect(ui.buttonChangeDevice, SIGNAL(clicked()), this, SLOT(configDialog()));
connect(ui.buttonEject, SIGNAL(clicked()), this, SLOT(eject()));
connect(ui.buttonTalk, SIGNAL(clicked()), this, SLOT(createTalkFiles()));
connect(ui.buttonCreateVoice, SIGNAL(clicked()), this, SLOT(createVoiceFile()));
connect(ui.buttonVoice, SIGNAL(clicked()), this, SLOT(installVoice()));
@ -733,3 +739,19 @@ void RbUtilQt::changeEvent(QEvent *e)
}
}
void RbUtilQt::eject(void)
{
QString mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
if(Utils::ejectDevice(mountpoint)) {
QMessageBox::information(this, tr("Device ejected"),
tr("Device successfully ejected. "
"You may now disconnect the player from the PC."));
}
else {
QMessageBox::critical(this, tr("Ejecting failed"),
tr("Ejecting the device failed. Please make sure no programs "
"are accessing files on the device. If ejecting still "
"fails please use your computers eject funtionality."));
}
}

View file

@ -79,6 +79,7 @@ class RbUtilQt : public QMainWindow
void help(void);
void sysinfo(void);
void trace(void);
void eject(void);
void configDialog(void);
void updateDevice(void);
void updateSettings(void);

View file

@ -19,6 +19,7 @@
<file>icons/edit-find.png</file>
<file>icons/font_btn.png</file>
<file>icons/go-next.png</file>
<file>icons/media-eject.png</file>
<file>icons/network-idle.png</file>
<file>icons/package-x-generic.png</file>
<file>icons/preferences-desktop-locale.png</file>

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>650</width>
<height>550</height>
<height>399</height>
</rect>
</property>
<property name="windowTitle">
@ -31,24 +31,25 @@
<string>Device</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QLabel" name="labelMountpoint">
<property name="text">
<string>mountpoint unknown or invalid</string>
<item row="0" column="0" rowspan="3">
<widget class="QLabel" name="labelPlayerPic">
<property name="lineWidth">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelMountpointTitle">
<property name="text">
<string>Mountpoint:</string>
<string/>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="labelDevice">
<property name="text">
<string>device unknown or invalid</string>
<property name="pixmap">
<pixmap resource="rbutilqt.qrc">:/icons/rockbox-32.png</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="margin">
<number>3</number>
</property>
</widget>
</item>
@ -65,6 +66,13 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="labelDevice">
<property name="text">
<string>device unknown or invalid</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
@ -78,17 +86,7 @@
</property>
</spacer>
</item>
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="labelPlayerPic">
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4" rowspan="2">
<item row="0" column="4">
<widget class="QPushButton" name="buttonChangeDevice">
<property name="text">
<string>&amp;Change</string>
@ -99,6 +97,31 @@
</property>
</widget>
</item>
<item row="1" column="4" rowspan="2">
<widget class="QPushButton" name="buttonEject">
<property name="text">
<string>&amp;Eject</string>
</property>
<property name="icon">
<iconset resource="rbutilqt.qrc">
<normaloff>:/icons/media-eject.png</normaloff>:/icons/media-eject.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelMountpointTitle">
<property name="text">
<string>Mountpoint:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="labelMountpoint">
<property name="text">
<string>mountpoint unknown or invalid</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -130,7 +153,7 @@
<item row="1" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>7</number>
<number>0</number>
</property>
<widget class="QWidget" name="selective">
<attribute name="title">
@ -388,7 +411,7 @@
<x>0</x>
<y>0</y>
<width>650</width>
<height>23</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">