summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Riebeling <Dominik.Riebeling@gmail.com>2012-09-08 20:34:36 +0200
committerDominik Riebeling <Dominik.Riebeling@gmail.com>2012-09-08 20:34:36 +0200
commit328ff6d979c028ecba9c57d12c1e75637be20396 (patch)
tree1373b766c7a1b0a6551816f105ee7447c0f602ae
parent4f99dd4264f9aaaccbf3da6bba37d5b2c7eb6f32 (diff)
downloadrockbox-328ff6d979c028ecba9c57d12c1e75637be20396.tar.gz
rockbox-328ff6d979c028ecba9c57d12c1e75637be20396.zip
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
-rw-r--r--rbutil/rbutilqt/base/utils.cpp60
-rw-r--r--rbutil/rbutilqt/base/utils.h1
-rw-r--r--rbutil/rbutilqt/icons/media-eject.pngbin0 -> 628 bytes
-rw-r--r--rbutil/rbutilqt/rbutilqt.cpp22
-rw-r--r--rbutil/rbutilqt/rbutilqt.h1
-rw-r--r--rbutil/rbutilqt/rbutilqt.qrc1
-rw-r--r--rbutil/rbutilqt/rbutilqtfrm.ui77
7 files changed, 135 insertions, 27 deletions
diff --git a/rbutil/rbutilqt/base/utils.cpp b/rbutil/rbutilqt/base/utils.cpp
index 3821b67201..cffa4b1cad 100644
--- a/rbutil/rbutilqt/base/utils.cpp
+++ b/rbutil/rbutilqt/base/utils.cpp
@@ -692,3 +692,63 @@ QStringList Utils::findRunningProcess(QStringList names)
692 qDebug() << "[Utils] Found listed processes running:" << found; 692 qDebug() << "[Utils] Found listed processes running:" << found;
693 return found; 693 return found;
694} 694}
695
696
697/** Eject device from PC.
698 * Request the OS to eject the player.
699 * @param device mountpoint of the device
700 * @return true on success, fals otherwise.
701 */
702bool Utils::ejectDevice(QString device)
703{
704#if defined(Q_OS_WIN32)
705 /* See http://support.microsoft.com/kb/165721 on the procedure to eject a
706 * device. */
707 bool success = false;
708 int i;
709 HANDLE hdl;
710 DWORD bytesReturned;
711 TCHAR volume[8];
712
713 /* CreateFile */
714 _stprintf(volume, _TEXT("\\\\.\\%c:"), device.toAscii().at(0));
715 hdl = CreateFile(volume, GENERIC_READ | GENERIC_WRITE,
716 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
717 OPEN_EXISTING, 0, NULL);
718 if(hdl == INVALID_HANDLE_VALUE)
719 return false;
720
721 /* lock volume to make sure no other application is accessing the volume.
722 * Try up to 10 times. */
723 for(i = 0; i < 10; i++) {
724 if(DeviceIoControl(hdl, FSCTL_LOCK_VOLUME,
725 NULL, 0, NULL, 0, &bytesReturned, NULL))
726 break;
727 /* short break before retry */
728 Sleep(100);
729 }
730 if(i < 10) {
731 /* successfully locked, now dismount */
732 if(DeviceIoControl(hdl, FSCTL_DISMOUNT_VOLUME,
733 NULL, 0, NULL, 0, &bytesReturned, NULL)) {
734 /* make sure media can be removed. */
735 PREVENT_MEDIA_REMOVAL pmr;
736 pmr.PreventMediaRemoval = false;
737 if(DeviceIoControl(hdl, IOCTL_STORAGE_MEDIA_REMOVAL,
738 &pmr, sizeof(PREVENT_MEDIA_REMOVAL),
739 NULL, 0, &bytesReturned, NULL)) {
740 /* eject the media */
741 if(DeviceIoControl(hdl, IOCTL_STORAGE_EJECT_MEDIA,
742 NULL, 0, NULL, 0, &bytesReturned, NULL))
743 success = true;
744 }
745 }
746 }
747 /* close handle */
748 CloseHandle(hdl);
749 return success;
750
751#endif
752 return false;
753}
754
diff --git a/rbutil/rbutilqt/base/utils.h b/rbutil/rbutilqt/base/utils.h
index 185c0323a6..db52bfb4e9 100644
--- a/rbutil/rbutilqt/base/utils.h
+++ b/rbutil/rbutilqt/base/utils.h
@@ -50,6 +50,7 @@ public:
50 static QString resolveDevicename(QString path); 50 static QString resolveDevicename(QString path);
51 static QString resolveMountPoint(QString device); 51 static QString resolveMountPoint(QString device);
52 static QStringList findRunningProcess(QStringList names); 52 static QStringList findRunningProcess(QStringList names);
53 static bool ejectDevice(QString device);
53}; 54};
54 55
55#endif 56#endif
diff --git a/rbutil/rbutilqt/icons/media-eject.png b/rbutil/rbutilqt/icons/media-eject.png
new file mode 100644
index 0000000000..2084067e94
--- /dev/null
+++ b/rbutil/rbutilqt/icons/media-eject.png
Binary files differ
diff --git a/rbutil/rbutilqt/rbutilqt.cpp b/rbutil/rbutilqt/rbutilqt.cpp
index 62a4f583f7..aa0c365303 100644
--- a/rbutil/rbutilqt/rbutilqt.cpp
+++ b/rbutil/rbutilqt/rbutilqt.cpp
@@ -110,6 +110,11 @@ RbUtilQt::RbUtilQt(QWidget *parent) : QMainWindow(parent)
110 RegCloseKey(hk); 110 RegCloseKey(hk);
111 } 111 }
112#endif 112#endif
113
114#if !defined(Q_OS_WIN32)
115 /* eject funtionality is only implemented on W32 right now. */
116 ui.buttonEject->setEnabled(false);
117#endif
113 updateDevice(); 118 updateDevice();
114 downloadInfo(); 119 downloadInfo();
115 120
@@ -142,6 +147,7 @@ RbUtilQt::RbUtilQt(QWidget *parent) : QMainWindow(parent)
142 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(configDialog())); 147 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(configDialog()));
143 connect(ui.actionE_xit, SIGNAL(triggered()), this, SLOT(shutdown())); 148 connect(ui.actionE_xit, SIGNAL(triggered()), this, SLOT(shutdown()));
144 connect(ui.buttonChangeDevice, SIGNAL(clicked()), this, SLOT(configDialog())); 149 connect(ui.buttonChangeDevice, SIGNAL(clicked()), this, SLOT(configDialog()));
150 connect(ui.buttonEject, SIGNAL(clicked()), this, SLOT(eject()));
145 connect(ui.buttonTalk, SIGNAL(clicked()), this, SLOT(createTalkFiles())); 151 connect(ui.buttonTalk, SIGNAL(clicked()), this, SLOT(createTalkFiles()));
146 connect(ui.buttonCreateVoice, SIGNAL(clicked()), this, SLOT(createVoiceFile())); 152 connect(ui.buttonCreateVoice, SIGNAL(clicked()), this, SLOT(createVoiceFile()));
147 connect(ui.buttonVoice, SIGNAL(clicked()), this, SLOT(installVoice())); 153 connect(ui.buttonVoice, SIGNAL(clicked()), this, SLOT(installVoice()));
@@ -733,3 +739,19 @@ void RbUtilQt::changeEvent(QEvent *e)
733 } 739 }
734} 740}
735 741
742void RbUtilQt::eject(void)
743{
744 QString mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
745 if(Utils::ejectDevice(mountpoint)) {
746 QMessageBox::information(this, tr("Device ejected"),
747 tr("Device successfully ejected. "
748 "You may now disconnect the player from the PC."));
749 }
750 else {
751 QMessageBox::critical(this, tr("Ejecting failed"),
752 tr("Ejecting the device failed. Please make sure no programs "
753 "are accessing files on the device. If ejecting still "
754 "fails please use your computers eject funtionality."));
755 }
756}
757
diff --git a/rbutil/rbutilqt/rbutilqt.h b/rbutil/rbutilqt/rbutilqt.h
index 1db100430a..350aca1956 100644
--- a/rbutil/rbutilqt/rbutilqt.h
+++ b/rbutil/rbutilqt/rbutilqt.h
@@ -79,6 +79,7 @@ class RbUtilQt : public QMainWindow
79 void help(void); 79 void help(void);
80 void sysinfo(void); 80 void sysinfo(void);
81 void trace(void); 81 void trace(void);
82 void eject(void);
82 void configDialog(void); 83 void configDialog(void);
83 void updateDevice(void); 84 void updateDevice(void);
84 void updateSettings(void); 85 void updateSettings(void);
diff --git a/rbutil/rbutilqt/rbutilqt.qrc b/rbutil/rbutilqt/rbutilqt.qrc
index 5305a98434..d1eea6872e 100644
--- a/rbutil/rbutilqt/rbutilqt.qrc
+++ b/rbutil/rbutilqt/rbutilqt.qrc
@@ -19,6 +19,7 @@
19 <file>icons/edit-find.png</file> 19 <file>icons/edit-find.png</file>
20 <file>icons/font_btn.png</file> 20 <file>icons/font_btn.png</file>
21 <file>icons/go-next.png</file> 21 <file>icons/go-next.png</file>
22 <file>icons/media-eject.png</file>
22 <file>icons/network-idle.png</file> 23 <file>icons/network-idle.png</file>
23 <file>icons/package-x-generic.png</file> 24 <file>icons/package-x-generic.png</file>
24 <file>icons/preferences-desktop-locale.png</file> 25 <file>icons/preferences-desktop-locale.png</file>
diff --git a/rbutil/rbutilqt/rbutilqtfrm.ui b/rbutil/rbutilqt/rbutilqtfrm.ui
index 85da42ed01..65348dabfb 100644
--- a/rbutil/rbutilqt/rbutilqtfrm.ui
+++ b/rbutil/rbutilqt/rbutilqtfrm.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>650</width> 9 <width>650</width>
10 <height>550</height> 10 <height>399</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -31,24 +31,25 @@
31 <string>Device</string> 31 <string>Device</string>
32 </property> 32 </property>
33 <layout class="QGridLayout" name="gridLayout"> 33 <layout class="QGridLayout" name="gridLayout">
34 <item row="1" column="2"> 34 <item row="0" column="0" rowspan="3">
35 <widget class="QLabel" name="labelMountpoint"> 35 <widget class="QLabel" name="labelPlayerPic">
36 <property name="text"> 36 <property name="lineWidth">
37 <string>mountpoint unknown or invalid</string> 37 <number>1</number>
38 </property> 38 </property>
39 </widget>
40 </item>
41 <item row="1" column="1">
42 <widget class="QLabel" name="labelMountpointTitle">
43 <property name="text"> 39 <property name="text">
44 <string>Mountpoint:</string> 40 <string/>
45 </property> 41 </property>
46 </widget> 42 <property name="pixmap">
47 </item> 43 <pixmap resource="rbutilqt.qrc">:/icons/rockbox-32.png</pixmap>
48 <item row="0" column="2"> 44 </property>
49 <widget class="QLabel" name="labelDevice"> 45 <property name="scaledContents">
50 <property name="text"> 46 <bool>false</bool>
51 <string>device unknown or invalid</string> 47 </property>
48 <property name="alignment">
49 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
50 </property>
51 <property name="margin">
52 <number>3</number>
52 </property> 53 </property>
53 </widget> 54 </widget>
54 </item> 55 </item>
@@ -65,6 +66,13 @@
65 </property> 66 </property>
66 </widget> 67 </widget>
67 </item> 68 </item>
69 <item row="0" column="2">
70 <widget class="QLabel" name="labelDevice">
71 <property name="text">
72 <string>device unknown or invalid</string>
73 </property>
74 </widget>
75 </item>
68 <item row="0" column="3"> 76 <item row="0" column="3">
69 <spacer name="horizontalSpacer"> 77 <spacer name="horizontalSpacer">
70 <property name="orientation"> 78 <property name="orientation">
@@ -78,24 +86,39 @@
78 </property> 86 </property>
79 </spacer> 87 </spacer>
80 </item> 88 </item>
81 <item row="0" column="0" rowspan="2"> 89 <item row="0" column="4">
82 <widget class="QLabel" name="labelPlayerPic"> 90 <widget class="QPushButton" name="buttonChangeDevice">
83 <property name="text"> 91 <property name="text">
84 <string/> 92 <string>&amp;Change</string>
85 </property> 93 </property>
86 <property name="scaledContents"> 94 <property name="icon">
87 <bool>true</bool> 95 <iconset resource="rbutilqt.qrc">
96 <normaloff>:/icons/edit-find.png</normaloff>:/icons/edit-find.png</iconset>
88 </property> 97 </property>
89 </widget> 98 </widget>
90 </item> 99 </item>
91 <item row="0" column="4" rowspan="2"> 100 <item row="1" column="4" rowspan="2">
92 <widget class="QPushButton" name="buttonChangeDevice"> 101 <widget class="QPushButton" name="buttonEject">
93 <property name="text"> 102 <property name="text">
94 <string>&amp;Change</string> 103 <string>&amp;Eject</string>
95 </property> 104 </property>
96 <property name="icon"> 105 <property name="icon">
97 <iconset resource="rbutilqt.qrc"> 106 <iconset resource="rbutilqt.qrc">
98 <normaloff>:/icons/edit-find.png</normaloff>:/icons/edit-find.png</iconset> 107 <normaloff>:/icons/media-eject.png</normaloff>:/icons/media-eject.png</iconset>
108 </property>
109 </widget>
110 </item>
111 <item row="1" column="1">
112 <widget class="QLabel" name="labelMountpointTitle">
113 <property name="text">
114 <string>Mountpoint:</string>
115 </property>
116 </widget>
117 </item>
118 <item row="1" column="2">
119 <widget class="QLabel" name="labelMountpoint">
120 <property name="text">
121 <string>mountpoint unknown or invalid</string>
99 </property> 122 </property>
100 </widget> 123 </widget>
101 </item> 124 </item>
@@ -130,7 +153,7 @@
130 <item row="1" column="0" colspan="2"> 153 <item row="1" column="0" colspan="2">
131 <widget class="QTabWidget" name="tabWidget"> 154 <widget class="QTabWidget" name="tabWidget">
132 <property name="currentIndex"> 155 <property name="currentIndex">
133 <number>7</number> 156 <number>0</number>
134 </property> 157 </property>
135 <widget class="QWidget" name="selective"> 158 <widget class="QWidget" name="selective">
136 <attribute name="title"> 159 <attribute name="title">
@@ -388,7 +411,7 @@
388 <x>0</x> 411 <x>0</x>
389 <y>0</y> 412 <y>0</y>
390 <width>650</width> 413 <width>650</width>
391 <height>23</height> 414 <height>21</height>
392 </rect> 415 </rect>
393 </property> 416 </property>
394 <widget class="QMenu" name="menu_File"> 417 <widget class="QMenu" name="menu_File">