Compare commits

..

257 Commits
0.1.6 ... 0.4.1

Author SHA1 Message Date
Jonas Kvinge
b782a2c8a2 Release 0.4.1 2018-11-01 21:18:57 +01:00
Jonas Kvinge
298783e2c5 Attempt to login if streamurl fails 2018-11-01 21:18:09 +01:00
Jonas Kvinge
bc9ec8025c Move some settings 2018-10-31 19:44:24 +01:00
Jonas Kvinge
26459763e5 Only set QtDebugMsg when build type is debug 2018-10-31 19:41:52 +01:00
Jonas Kvinge
1213306657 Update libcdio 2018-10-31 01:30:15 +01:00
Jonas Kvinge
50add12e4b Update changelog 2018-10-30 23:47:51 +01:00
Jonas Kvinge
67c889f982 Improve Xine engine code 2018-10-30 23:40:41 +01:00
Jonas Kvinge
08cba25071 Improve VLC error handling 2018-10-30 23:40:05 +01:00
Jonas Kvinge
ff35b01bac Improve gst engine error handling 2018-10-30 23:39:08 +01:00
Jonas Kvinge
faee1977fe Add better error handling between engine and player 2018-10-30 23:21:51 +01:00
Jonas Kvinge
6105b99a7f Add option to continue to next song in playlist on error
Also rename some settings. Add option to grey out songs both on playback and
on startup.
2018-10-30 23:20:02 +01:00
Jonas Kvinge
4993201b70 Fix deezer url handler 2018-10-30 23:18:25 +01:00
Jonas Kvinge
f456ca674d Update taglib 2018-10-27 12:15:52 +02:00
Jonas Kvinge
2ba350f76f Attempt to fix crash in setStyleSheet() 2018-10-26 20:05:37 +02:00
Jonas Kvinge
3fe92a62ac Add DSF and DSDIFF to IsFileLossless 2018-10-24 00:58:03 +02:00
Jonas Kvinge
f4dcf6821f Rename class InternetModel to InternetServices 2018-10-23 23:25:02 +02:00
Jonas Kvinge
0c10013858 Ops 2018-10-23 21:14:58 +02:00
Jonas Kvinge
3e9530fa8d Set metadata from deezer engine 2018-10-23 20:21:33 +02:00
Jonas Kvinge
0f4ffe4fce Add PCM as filetype 2018-10-23 20:21:01 +02:00
Jonas Kvinge
e1c01e5d25 Fix device selection 2018-10-23 20:18:07 +02:00
Jonas Kvinge
51021131d7 Allow compile on Qt 5.5.1 or above 2018-10-23 20:17:29 +02:00
Jonas Kvinge
89a08d1d5e Fix RPM build 2018-10-22 23:23:25 +02:00
Jonas Kvinge
ba8717f95a Fix Deezer engine error state 2018-10-22 23:04:34 +02:00
Jonas Kvinge
c8dfb9b0db Fix loading custom device 2018-10-22 22:10:27 +02:00
Jonas Kvinge
3a02ece169 Add EnsureInitialised() 2018-10-22 20:40:02 +02:00
Jonas Kvinge
262df6b461 Merge pull request #24 from eclipseo/use_qt5_deps
Use qt5 libraries of system-wide libraries
2018-10-22 19:00:07 +02:00
Jonas Kvinge
b9516fdfd4 Merge pull request #23 from eclipseo/add_appdata_file
Add AppStream data file
2018-10-22 18:49:28 +02:00
Robert-André Mauchin
9de41bc027 Use qt5 version of system-wide libraries 2018-10-22 17:45:47 +02:00
Robert-André Mauchin
53b5cf3855 Add AppStream data file 2018-10-22 16:44:35 +02:00
Jonas Kvinge
0567358783 Update README.md 2018-10-21 20:49:35 +02:00
Jonas Kvinge
c97bc55c6f Move queuemanager to fancytabbar 2018-10-21 15:13:48 +02:00
Jonas Kvinge
3ef0bf60d0 Correct text for right click configure 2018-10-20 22:33:23 +02:00
Jonas Kvinge
b7b8084a38 Remove setExpanding 2018-10-20 22:18:56 +02:00
Jonas Kvinge
5221f13498 Minor code cleanup and fixes 2018-10-20 22:16:22 +02:00
Jonas Kvinge
0c0a8d70f3 Change darwin to macos 2018-10-20 22:15:32 +02:00
Jonas Kvinge
2ff971878d Enable debug logging on Fedora 2018-10-20 22:13:51 +02:00
Jonas Kvinge
1a0dc1e614 Update README 2018-10-20 22:13:21 +02:00
Jonas Kvinge
4a0bd99654 Enable deezer engine by default 2018-10-20 22:13:02 +02:00
Jonas Kvinge
5cb98e44cb Update README 2018-10-19 20:42:58 +02:00
Jonas Kvinge
13ed99b9c3 Update README and Changelog 2018-10-19 20:37:42 +02:00
Jonas Kvinge
0cda4e27aa Replace qSort/qStableSort/qSwap 2018-10-19 20:18:46 +02:00
Jonas Kvinge
0969e7f504 Remove cachedlist.h 2018-10-19 19:38:30 +02:00
Jonas Kvinge
cad73e18e2 Remove unused code 2018-10-19 19:20:29 +02:00
Jonas Kvinge
9eadeddfd9 Fixup and finish deezer engine 2018-10-19 19:15:33 +02:00
Jonas Kvinge
de11cb173b Use previews as default setting if deezer engine and dzmedia is missing 2018-10-19 19:14:49 +02:00
Jonas Kvinge
5853bc68d1 Replace depreciated macro 2018-10-19 19:13:40 +02:00
Jonas Kvinge
7d1fd9d46f Add missing names 2018-10-19 19:13:24 +02:00
Jonas Kvinge
c977c822d5 Add info about Deezer 2018-10-19 19:13:01 +02:00
Jonas Kvinge
c05fb33ea2 Replace FancyTabWidget with improved version 2018-10-19 19:10:22 +02:00
Jonas Kvinge
b9d0b3e152 Add option to diable Tidal and Deezer 2018-10-17 23:49:02 +02:00
Jonas Kvinge
a9e905b301 Fix bug not loading engine 2018-10-17 22:55:36 +02:00
Jonas Kvinge
a8a714c820 Use common classes for Tidal and Deezer 2018-10-17 21:18:39 +02:00
Jonas Kvinge
9349ad9383 Fix missing icon 2018-10-17 00:46:08 +02:00
Jonas Kvinge
f686f00951 Fix missing icon 2018-10-17 00:43:05 +02:00
Jonas Kvinge
3d13c12cb7 Update taglib 2018-10-16 23:58:26 +02:00
Jonas Kvinge
2384a42d33 Update .gitignore 2018-10-16 21:37:27 +02:00
Jonas Kvinge
f507fec905 Update Changelog 2018-10-16 21:32:03 +02:00
Jonas Kvinge
83a9724d17 Improve Tidal code 2018-10-16 21:31:28 +02:00
Jonas Kvinge
4156e26f76 Fix some minor code bugs in deezer 2018-10-16 21:30:27 +02:00
Jonas Kvinge
6d269e1786 Add libdeezer dll to windows nsi 2018-10-16 21:29:40 +02:00
Jonas Kvinge
ea447cab37 Remove quotes 2018-10-16 21:29:21 +02:00
Jonas Kvinge
4f3e7de441 Exclude debian changelog 2018-10-16 21:29:00 +02:00
Jonas Kvinge
0a81fa99fc Add Deezer support 2018-10-14 00:08:33 +02:00
Jonas Kvinge
4aad44cb62 Create timer for login attempts for Tidal 2018-10-13 00:30:52 +02:00
Jonas Kvinge
69dda39d02 Create timer for login attempts for Tidal 2018-10-13 00:18:38 +02:00
Jonas Kvinge
ca3ba6f136 Increase kTrackSliderUpdateTimeMs 2018-10-02 01:01:31 +02:00
Jonas Kvinge
044cf4624a Add hide() 2018-10-02 00:58:46 +02:00
Jonas Kvinge
1fbfabdf66 Remove whitespaces 2018-10-02 00:46:54 +02:00
Jonas Kvinge
db035351be Remove whitespaces 2018-10-02 00:38:52 +02:00
Jonas Kvinge
2883ef840e Fix track stop on error 2018-10-02 00:21:50 +02:00
Jonas Kvinge
8254ee911d Fix default setting for system tray 2018-10-01 00:31:02 +02:00
Jonas Kvinge
560bc0a150 Fix default setting for system tray 2018-10-01 00:29:06 +02:00
Jonas Kvinge
827898cd38 Fix taglib includes 2018-09-30 22:32:56 +02:00
Jonas Kvinge
184dec146c Move resume playback outside of startup group 2018-09-30 15:55:02 +02:00
Jonas Kvinge
298dbe96c8 Check if system has system tray using QSystemTrayIcon::isSystemTrayAvailable() 2018-09-30 15:33:27 +02:00
Jonas Kvinge
6d888eb51a Analyzer code cleanup and try to fix crash on Fedora 2018-09-30 15:32:21 +02:00
Jonas Kvinge
3694765611 Add error handling for enabling FTS3 2018-09-30 14:54:14 +02:00
Jonas Kvinge
b07ae3d34e Remove reset 2018-09-30 00:08:09 +02:00
Jonas Kvinge
64bcdf4734 Fix spelling 2018-09-30 00:07:59 +02:00
Jonas Kvinge
1c23756fc4 Turn on git revision 2018-09-30 00:07:05 +02:00
Jonas Kvinge
50e3eeaafd Release 0.3.3 2018-09-24 19:13:45 +02:00
Jonas Kvinge
843f528ebc Revert change to Tidal login using clientUniqueKey 2018-09-24 19:10:49 +02:00
Jonas Kvinge
faa0076988 Turn back git revision 2018-09-24 19:10:15 +02:00
Jonas Kvinge
59622c52ad Release 0.3.2 2018-09-24 18:42:21 +02:00
Jonas Kvinge
a8e9aba58b Save password as QString 2018-09-24 18:40:05 +02:00
Jonas Kvinge
36563cd1e1 Fix compile 2018-09-22 23:32:11 +02:00
Jonas Kvinge
072e712f0d Add missing QUrl include 2018-09-22 23:30:19 +02:00
Jonas Kvinge
121a186160 Improve contextview and engine code 2018-09-22 23:13:56 +02:00
Jonas Kvinge
15a2ccc21e Change size of comboxes in device settings 2018-09-22 15:54:38 +02:00
Jonas Kvinge
dbd8ea69eb Turn off debug about in Tidal 2018-09-22 15:39:24 +02:00
Jonas Kvinge
8a57356f64 More Tidal fixes 2018-09-22 15:37:42 +02:00
Jonas Kvinge
c77cb002f3 Add support for both ALSA hw and plughw 2018-09-21 23:29:00 +02:00
Jonas Kvinge
aa83a2b40b Add option to change url stream scheme for Tidal 2018-09-21 18:53:27 +02:00
Jonas Kvinge
65b04cac6e Update changelog 2018-09-21 01:20:16 +02:00
Jonas Kvinge
5e577190a8 Fix some copyrights 2018-09-21 01:12:21 +02:00
Jonas Kvinge
0143617056 Fix bug setting wrong temp metadata and bug in pipeline 2018-09-21 00:34:02 +02:00
Jonas Kvinge
a77dde7d3b Fix some includes 2018-09-20 22:48:52 +02:00
Jonas Kvinge
7dcdb7c673 Might be a good idea to actually add the URL Handler :) 2018-09-20 22:37:38 +02:00
Jonas Kvinge
6de8eb56cd Remove dead code in Tidal 2018-09-20 22:29:35 +02:00
Jonas Kvinge
04e272d9bc Fix mistake 2018-09-20 22:22:48 +02:00
Jonas Kvinge
17fe201473 Use URL Handler for Tidal 2018-09-20 22:13:30 +02:00
Jonas Kvinge
25249be37f Change orange to red 2018-09-20 17:44:31 +02:00
Jonas Kvinge
97ec12b5b3 Don't compile devices on windows 2018-09-20 17:36:23 +02:00
Jonas Kvinge
246f82bfad Replace obsolete QStyleOptionViewItemV2-4 2018-09-18 22:17:28 +02:00
Jonas Kvinge
db5679bbe9 Fix lsb-release command 2018-09-18 19:01:59 +02:00
Jonas Kvinge
feb0e1c45b Fix Fedora RPM suffix 2018-09-18 18:43:04 +02:00
Jonas Kvinge
edba837295 Fix RPM Suffix 2018-09-18 17:28:49 +02:00
Jonas Kvinge
55882360ef Fix RPM suffix 2018-09-18 00:45:33 +02:00
Jonas Kvinge
6039370ad6 Fix exclude 2018-09-18 00:45:07 +02:00
Jonas Kvinge
2d238c08d3 Change output filename 2018-09-18 00:31:21 +02:00
Jonas Kvinge
9b337b6a34 Add missing nsi 2018-09-17 19:30:23 +02:00
Jonas Kvinge
370db791aa Add nsi files for x86_64-w64-mingw32 2018-09-17 01:02:48 +02:00
Jonas Kvinge
9e3c547580 Turn back on git revision 2018-09-16 23:13:30 +02:00
Jonas Kvinge
ab5d9b62b8 Fix search error not shown in Tidal search 2018-09-15 22:34:44 +02:00
Jonas Kvinge
8e35e0c476 Release 0.3.1 2018-09-15 19:22:55 +02:00
Jonas Kvinge
9d9492b528 Update README.md 2018-09-15 13:46:29 +02:00
Jonas Kvinge
9732cc2ce2 Update README.md 2018-09-15 13:45:26 +02:00
Jonas Kvinge
a4beea3f34 Update README.md 2018-09-15 13:43:33 +02:00
Jonas Kvinge
c9256c52bf Check for QT version 2018-09-15 13:35:03 +02:00
Jonas Kvinge
6563bec7e4 Remove builtin qtwin and use WinExtras, replace some macros 2018-09-15 13:07:51 +02:00
Jonas Kvinge
072facdf7b Update features 2018-09-15 00:22:10 +02:00
Jonas Kvinge
a0f07a7a67 Update about 2018-09-14 23:58:58 +02:00
Jonas Kvinge
1a7465ba94 Formatting and remove unused icons 2018-09-14 23:05:58 +02:00
Jonas Kvinge
be3862ec40 Add missing signal 2018-09-12 22:55:53 +02:00
Jonas Kvinge
a5276a3b7e Merge branch 'master' of github.com:jonaski/strawberry 2018-09-12 22:52:09 +02:00
Jonas Kvinge
fc8a27f55b Fix some compiler warnings 2018-09-12 22:51:10 +02:00
Jonas Kvinge
87718bee24 Update .travis.yml 2018-09-12 22:15:19 +02:00
Jonas Kvinge
56f2e00990 Update .travis.yml 2018-09-12 22:14:37 +02:00
Jonas Kvinge
27e3448dda Merge branch 'master' of github.com:jonaski/strawberry 2018-09-12 21:52:52 +02:00
Jonas Kvinge
9404e40cad Fix song.h 2018-09-12 21:52:30 +02:00
Jonas Kvinge
982f399aff Update .travis.yml 2018-09-12 21:17:45 +02:00
Jonas Kvinge
6d373737db Update .travis.yml 2018-09-12 21:09:00 +02:00
Jonas Kvinge
7f9e196234 Update .travis.yml 2018-09-12 20:56:51 +02:00
Jonas Kvinge
95d03de160 Update .travis.yml 2018-09-12 20:12:34 +02:00
Jonas Kvinge
d43190a41f Update .travis.yml 2018-09-12 19:45:46 +02:00
Jonas Kvinge
b5c0529969 Update .travis.yml 2018-09-12 19:42:04 +02:00
Jonas Kvinge
621a5b1de8 Update Dockerfile 2018-09-12 19:32:13 +02:00
Jonas Kvinge
e30f269412 Update .travis.yml 2018-09-11 23:32:19 +02:00
Jonas Kvinge
494ac20cca Create Dockerfile 2018-09-11 23:13:58 +02:00
Jonas Kvinge
bf997a6d2e Don't show error when there was no match from API Seeds 2018-09-11 00:38:06 +02:00
Jonas Kvinge
bc0c0b7950 Extract error from Json data in API Seeds 2018-09-11 00:20:24 +02:00
Jonas Kvinge
f202cf6988 Don't use lyrics from AudD if title and artist don't match 2018-09-11 00:01:17 +02:00
Jonas Kvinge
e62fb964ff Improve lyrics providers 2018-09-10 23:46:01 +02:00
Jonas Kvinge
9014781336 Fix Tidal authentication 2018-09-10 22:22:00 +02:00
Jonas Kvinge
e479e7e113 Fix show album cover from Tidal 2018-09-10 21:58:57 +02:00
Jonas Kvinge
f9379961e9 Fix Tidal authentication 2018-09-10 21:23:50 +02:00
Jonas Kvinge
e5e6cbf6e4 Hide samplerate, bitdepth and bitrate when not set 2018-09-08 13:25:40 +02:00
Jonas Kvinge
6d686ee66a Add source to songs and playlist_items 2018-09-08 12:38:02 +02:00
Jonas Kvinge
19b645d731 Show filetype for Tidal 2018-09-06 22:34:18 +02:00
Jonas Kvinge
28c685dcd8 Ops I did it again... 2018-09-06 20:51:14 +02:00
Jonas Kvinge
0abeefd470 Fixed saving (APE) tags for WavPack files 2018-09-06 20:49:05 +02:00
Jonas Kvinge
1562585561 Added support for reading lyrics from tags
Also fixed tagreader crash when saving tags to MP3 files
2018-09-06 20:04:29 +02:00
Jonas Kvinge
0a64a2a394 Finish Tidal
- Add configurable settings
- Add progressbar
- Simplify code
2018-09-06 17:39:26 +02:00
Jonas Kvinge
440a223bfb Fix saving search_for_cover_auto 2018-09-06 17:37:50 +02:00
Jonas Kvinge
36b0a22c79 Fix saving above_status_bar 2018-09-06 17:37:03 +02:00
Jonas Kvinge
032022c246 Add "Show above status bar" as an option 2018-09-05 19:03:21 +02:00
Jonas Kvinge
9e4f3f9867 Fix qocoa mac build 2018-09-05 18:15:28 +02:00
Jonas Kvinge
1119c87b2f Fix clear search box 2018-09-04 22:55:38 +02:00
Jonas Kvinge
36ab26c49a Fix automatic album cover fetching
- Moved Album Choice Controller to mainwindow to use common for both
PlayingWidget and ContextView.
- Fixed a bug I created that caused fetching album covers in a loop
2018-09-04 21:43:44 +02:00
Jonas Kvinge
460cddb3dc Add ResetWarning() to make sure label is hidden 2018-09-04 20:52:47 +02:00
Jonas Kvinge
a5c2dfacf0 Don't use discogs for automatic album cover search 2018-09-04 20:51:47 +02:00
Jonas Kvinge
b9788ef4b5 Update .travis.yml 2018-09-02 23:49:28 +02:00
Jonas Kvinge
4a124e596e Update .travis.yml 2018-09-02 17:04:58 +02:00
Jonas Kvinge
994a400ac9 Update nsi files 2018-09-02 16:20:48 +02:00
Jonas Kvinge
d08e6a1dca Remove libmpcdec-5.dll 2018-09-02 16:00:48 +02:00
Jonas Kvinge
154136185b Remove libxine from nsi file 2018-09-02 12:56:31 +02:00
Jonas Kvinge
f86b10c71f Add bold to albums by label 2018-09-02 12:50:28 +02:00
Jonas Kvinge
0b3d84a65e Update changelog 2018-09-02 12:50:12 +02:00
Jonas Kvinge
ee78b6f2bb Add DSF and DSDIFF/DFF support 2018-09-02 01:40:14 +02:00
Jonas Kvinge
521d5cf4fa Add DSF and DSDIFF support to taglib 2018-09-02 01:39:02 +02:00
Jonas Kvinge
52cf4412c8 Update changelog 2018-09-01 22:22:12 +02:00
Jonas Kvinge
dcae67ac7b Change search limit 2018-09-01 22:21:45 +02:00
Jonas Kvinge
cd0ee282c6 Add dist/windows/strawberry-debug.nsi.in to cmake 2018-09-01 22:14:59 +02:00
Jonas Kvinge
9d7e5864de Merge branch 'master' of github.com:jonaski/strawberry 2018-09-01 22:00:44 +02:00
Jonas Kvinge
d426eb2e07 Add seperate nsi file for debug 2018-09-01 22:00:06 +02:00
Jonas Kvinge
06bed7feb7 Update README.md 2018-08-29 23:26:14 +02:00
Jonas Kvinge
adc38c4b12 Disable Amazon cover provider (API key revoked) 2018-08-29 22:27:26 +02:00
Jonas Kvinge
5af58c19ae Remove some unused variables 2018-08-29 22:17:23 +02:00
Jonas Kvinge
ac6cac8da1 New context with albums and lyrics +++ much more
* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
* Fixed playing and context widget getting stuck in play mode when there was an error
* Changed icons for artists in collection, tidal and cover manager
* Removed "search" icon from "Search automatically" checkbox (right click) that looked ugly
* Removed some unused widgets from the src/widgets directory
* Fixed initial size of window and side panel
* Fixed saving window size correctly
2018-08-29 21:42:24 +02:00
Jonas Kvinge
3b30e66e87 Fix DB schema 2018-08-15 01:28:37 +02:00
Jonas Kvinge
41b0b1efd4 Remove broken xine fader until it's properly fixed 2018-08-12 15:05:34 +02:00
Jonas Kvinge
099d098dc7 Remove install log 2018-08-10 22:01:59 +02:00
Jonas Kvinge
1a55b7f1b2 Add DLL's required for Tidal to windows installer 2018-08-09 23:31:24 +02:00
Jonas Kvinge
f5ba8da3c7 Remove info frame from DeviceViewContainer
Was broken and caused yellow background on windows
2018-08-09 22:30:18 +02:00
Jonas Kvinge
08fcedd925 Rename some UI stuff 2018-08-09 21:49:18 +02:00
Jonas Kvinge
57f6f40e7d Fix missing icons and rework some UI stuff 2018-08-09 21:04:30 +02:00
Jonas Kvinge
4ca99dde43 Remove bak file 2018-08-09 18:41:43 +02:00
Jonas Kvinge
c518e42e18 Remove whitespace 2018-08-09 18:39:44 +02:00
Jonas Kvinge
0c329e6d83 Update README.md 2018-08-09 18:21:57 +02:00
Jonas Kvinge
820124f9e1 Add tidal support 2018-08-09 18:10:03 +02:00
Jonas Kvinge
26062bd07b Remove unneeded include 2018-07-28 00:16:56 +02:00
Jonas Kvinge
73029ab7a2 Remove dead analyzer code from VLC engine 2018-07-28 00:09:39 +02:00
Jonas Kvinge
c3e916d945 Add some missing e-mails in about 2018-07-20 02:28:42 +02:00
Jonas Kvinge
6ee9f9d1ad Add some missing names to about 2018-07-20 02:07:47 +02:00
Jonas Kvinge
b2c26eb4ed Make chromaprint optional 2018-07-16 07:23:37 +02:00
Jonas Kvinge
e181b47e3f Add 'make deb' 2018-07-16 02:57:57 +02:00
Jonas Kvinge
dc91f19f30 Just use PkgConfig to find dbus
- dbus was not found on debian based distros, because they had the library in a different location
- Not sure why I added the find package cmake file in the first place, will fix it and readd it if this causes problems
2018-07-16 01:20:29 +02:00
Jonas Kvinge
e260fc5057 Add check for qpa/qplatformnativeinterface.h in qxt 2018-07-16 01:18:58 +02:00
Jonas Kvinge
2368fff243 Fix mistake 2018-07-12 17:17:20 +02:00
Jonas Kvinge
70db0a33d1 Add debian package 2018-07-12 17:10:38 +02:00
Jonas Kvinge
56f47909f4 Fix Fedora build 2018-07-12 01:51:31 +02:00
Jonas Kvinge
e22b47a9d1 Revert git version off for Windows 2018-07-12 00:18:55 +02:00
Jonas Kvinge
e32ed02a24 Fix RPM build 2018-07-12 00:07:29 +02:00
Jonas Kvinge
eb5d72a940 Fix build with cmake with < 3.1 2018-07-11 17:23:44 +02:00
Jonas Kvinge
cbd809621a Update README.md 2018-07-08 19:50:16 +02:00
Jonas Kvinge
ad5d5d0ecd Correct Qt 5 dependencies 2018-07-06 21:56:13 +02:00
Jonas Kvinge
6bc948453c Update README.md 2018-07-05 19:47:18 +02:00
Jonas Kvinge
803590daa8 Fix Travis-CI build 2018-07-05 19:11:47 +02:00
Jonas Kvinge
c63399ee98 Update .travis.yml 2018-07-05 18:56:14 +02:00
Jonas Kvinge
f5ff95dca4 Update .travis.yml 2018-07-05 18:44:46 +02:00
Jonas Kvinge
998357c0bb Update .travis.yml 2018-07-05 18:33:50 +02:00
Jonas Kvinge
b43331bc3c Update .travis.yml 2018-07-05 18:17:36 +02:00
Jonas Kvinge
ecfeb17869 Update .travis.yml 2018-07-05 18:08:18 +02:00
Jonas Kvinge
9d2c9c732e Update .travis.yml 2018-07-05 18:02:24 +02:00
Jonas Kvinge
6478fadedc Update .travis.yml 2018-07-05 17:58:53 +02:00
Jonas Kvinge
a62eaa919d Update README.md 2018-07-05 17:56:25 +02:00
Jonas Kvinge
328a86288c Update .travis.yml 2018-07-05 17:52:32 +02:00
Jonas Kvinge
f1902a5b63 Update .travis.yml 2018-07-05 17:42:16 +02:00
Jonas Kvinge
693bade5a6 Update .travis.yml 2018-07-05 17:34:58 +02:00
Jonas Kvinge
ca2acb177a Create .travis.yml 2018-07-05 17:18:49 +02:00
Jonas Kvinge
670cd4e081 Remove unused variable 2018-07-05 03:28:32 +02:00
Jonas Kvinge
3a228c42bb Release 0.2.1 2018-07-05 02:55:51 +02:00
Jonas Kvinge
73fd87f8aa Update README.md 2018-07-04 14:25:36 +02:00
Jonas Kvinge
3adc1b55fa Update dist/windows/strawberry.nsi 2018-07-04 14:20:02 +02:00
Jonas Kvinge
0fd31f3632 Turn off git revision for windows build 2018-07-04 03:10:27 +02:00
Jonas Kvinge
55e0255fc2 Update windows/strawberry.nsi 2018-07-04 02:53:27 +02:00
Jonas Kvinge
8d23f6c422 Update dist/windows/strawberry.nsi 2018-07-04 01:57:22 +02:00
Jonas Kvinge
8aebfdc88c Fix dbus compile in osd widget 2018-07-04 00:55:09 +02:00
Jonas Kvinge
a554032823 Fix compile without dbus 2018-07-03 21:21:33 +02:00
Jonas Kvinge
c818ce19e9 Show engine switch warning only if more than 1 2018-07-03 20:36:38 +02:00
Jonas Kvinge
602f9759bb Fix dbus compile without X11 2018-07-03 20:32:28 +02:00
Jonas Kvinge
a00b8b2dca Use HAVE_DBUS instead of QT_DBUS_LIB 2018-07-03 19:48:08 +02:00
Jonas Kvinge
6dccc8857b Cleanup linking of QT components 2018-07-03 19:33:09 +02:00
Jonas Kvinge
b0f86a38ca Replace fromAscii() with fromLatin1() 2018-07-03 19:31:49 +02:00
Jonas Kvinge
1e4088b3e5 Make macdevicelister compile 2018-07-03 19:30:54 +02:00
Jonas Kvinge
3c5da3c8bd Update spec file 2018-07-03 18:55:25 +02:00
Jonas Kvinge
8e9bf2653a Update README.md 2018-07-03 18:24:34 +02:00
Jonas Kvinge
0d6f377664 Update README.md 2018-07-03 18:23:05 +02:00
Jonas Kvinge
d30a63f79b Fix variable 2018-07-03 17:56:13 +02:00
Jonas Kvinge
ab3569a285 More macos fixes 2018-07-03 17:51:52 +02:00
Jonas Kvinge
efdaf57f99 Bummer 2018-07-01 22:35:09 +02:00
Jonas Kvinge
ada7325a04 Fix macos build 2018-07-01 22:26:46 +02:00
Jonas Kvinge
c4e75dea65 Fix macos build 2018-07-01 22:24:23 +02:00
Jonas Kvinge
41ce19ab97 Correct spelling 2018-07-01 15:35:34 +02:00
Jonas Kvinge
3894419b14 More engine fixes 2018-07-01 15:30:53 +02:00
Jonas Kvinge
af03c05559 Make cmake fail if git revision cant be set. 2018-07-01 15:29:35 +02:00
Jonas Kvinge
04f1d296ea More engine fixes 2018-07-01 01:29:52 +02:00
Jonas Kvinge
67df8f2243 Hide warning groupbox in backend settings 2018-06-29 00:57:26 +02:00
Jonas Kvinge
980d8a65a1 Hide warning label in backend settings when not shown. 2018-06-29 00:33:30 +02:00
Jonas Kvinge
fc66e2e2c7 Fixes to xine engine 2018-06-28 23:12:39 +02:00
Jonas Kvinge
505c1feb42 Merge branch 'master' of github.com:jonaski/strawberry 2018-06-28 01:17:24 +02:00
Jonas Kvinge
985b91e5f4 Fix setting output/device for Xine and VLC backend
- Fixed setting output and device on Xine and VLC backend
- Fixed track slider for Xine, VLC and Phonon
- Improved backend settings to better support multiple backends
- Added group by samplerate and bitdepth in collection
- Fixed crash on exit when existing instance of the application is already runnung caused by NVIDIA driver
- Changed Q_OS_MAC to Q_OS_MACOS
2018-06-28 01:15:32 +02:00
Jonas Kvinge
ef7b95220c Update README.md 2018-06-21 01:50:14 +02:00
Jonas Kvinge
6978983dd3 Update README.md 2018-06-20 15:31:37 +02:00
Jonas Kvinge
008c39cd00 Add gstsink to devicefinder 2018-06-17 15:07:11 +02:00
Jonas Kvinge
416beb6b8e Use BOOST_SCOPE_EXIT 2018-06-12 00:26:08 +02:00
Jonas Kvinge
c4e64b591d Fix crash 2018-06-11 22:35:46 +02:00
720 changed files with 27920 additions and 11788 deletions

5
.gitignore vendored
View File

@@ -34,6 +34,11 @@ Thumbs.db
*.rc
/.qmake.cache
/.qmake.stash
*.spec
*.nsi
*.plist
maketarball.sh
dist/debian/changelog
# qtcreator generated files
*.pro.user*

30
.travis.yml Normal file
View File

@@ -0,0 +1,30 @@
sudo: required
language: C++
os:
- linux
- osx
services:
- docker
compiler:
- gcc
- clang
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -f Dockerfile -t strawberry-build . ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run --name build -itd strawberry-build /bin/bash ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build git clone https://github.com/jonaski/strawberry ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib pkgconfig protobuf protobuf-c qt ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sqlite --with-fts ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gstreamer gst-plugins-base ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-good --with-flac ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-bad gst-plugins-ugly ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install chromaprint ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export Qt5_DIR=/usr/local/opt/qt5/lib/cmake ; fi
before_script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DFORCE_GIT_REVISION="0.0.0-0-g0000000"; fi
script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make -j8 ; fi

13
3rdparty/SPMediaKeyTap/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,13 @@
set(SPMEDIAKEY-SOURCES
SPMediaKeyTap.m
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
)
set(SPMEDIAKEY-HEADERS
SPMediaKeyTap.h
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
)
ADD_LIBRARY(SPMediaKeyTap STATIC
${SPMEDIAKEY-SOURCES}
)

8
3rdparty/SPMediaKeyTap/LICENSE vendored Normal file
View File

@@ -0,0 +1,8 @@
Copyright (c) 2011, Joachim Bengtsson
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

12
3rdparty/SPMediaKeyTap/README.md vendored Normal file
View File

@@ -0,0 +1,12 @@
SPMediaKeyTap
=============
`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple are not exposing any APIs allowing third-parties to join in on this collaboration.
For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon.
In `Example/SPMediaKeyTapExampleAppDelegate.m` is an example of both how you use `SPMediaKeyTap`, and how you handle the semi-private `NSEvent` subtypes involved in media keys, including on how to fall back to non-event tap handling of these events.
`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active.
`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4.

View File

@@ -0,0 +1,30 @@
#import <Foundation/Foundation.h>
@interface SPInvocationGrabber : NSObject {
id _object;
NSInvocation *_invocation;
int frameCount;
char **frameStrings;
BOOL backgroundAfterForward;
BOOL onMainAfterForward;
BOOL waitUntilDone;
}
-(id)initWithObject:(id)obj;
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
@property (readonly, retain, nonatomic) id object;
@property (readonly, retain, nonatomic) NSInvocation *invocation;
@property BOOL backgroundAfterForward;
@property BOOL onMainAfterForward;
@property BOOL waitUntilDone;
-(void)invoke; // will release object and invocation
-(void)printBacktrace;
-(void)saveBacktrace;
@end
@interface NSObject (SPInvocationGrabbing)
-(id)grab;
-(id)invokeAfter:(NSTimeInterval)delta;
-(id)nextRunloop;
-(id)inBackground;
-(id)onMainAsync:(BOOL)async;
@end

View File

@@ -0,0 +1,128 @@
#import "NSObject+SPInvocationGrabbing.h"
#import <execinfo.h>
#pragma mark Invocation grabbing
@interface SPInvocationGrabber ()
@property (readwrite, retain, nonatomic) id object;
@property (readwrite, retain, nonatomic) NSInvocation *invocation;
@end
@implementation SPInvocationGrabber
- (id)initWithObject:(id)obj;
{
return [self initWithObject:obj stacktraceSaving:YES];
}
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
{
self.object = obj;
if(saveStack)
[self saveBacktrace];
return self;
}
-(void)dealloc;
{
free(frameStrings);
self.object = nil;
self.invocation = nil;
[super dealloc];
}
@synthesize invocation = _invocation, object = _object;
@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
- (void)runInBackground;
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
[self invoke];
}
@finally {
[pool drain];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
[anInvocation retainArguments];
anInvocation.target = _object;
self.invocation = anInvocation;
if(backgroundAfterForward)
[NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
else if(onMainAfterForward)
[self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
if (signature == NULL)
signature = [_object methodSignatureForSelector:inSelector];
return signature;
}
- (void)invoke;
{
@try {
[_invocation invoke];
}
@catch (NSException * e) {
NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
[self printBacktrace];
printf("\n");
[e raise];
}
self.invocation = nil;
self.object = nil;
}
-(void)saveBacktrace;
{
void *backtraceFrames[128];
frameCount = backtrace(&backtraceFrames[0], 128);
frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
}
-(void)printBacktrace;
{
int x;
for(x = 3; x < frameCount; x++) {
if(frameStrings[x] == NULL) { break; }
printf("%s\n", frameStrings[x]);
}
}
@end
@implementation NSObject (SPInvocationGrabbing)
-(id)grab;
{
return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease];
}
-(id)invokeAfter:(NSTimeInterval)delta;
{
id grabber = [self grab];
[NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
return grabber;
}
- (id)nextRunloop;
{
return [self invokeAfter:0];
}
-(id)inBackground;
{
SPInvocationGrabber *grabber = [self grab];
grabber.backgroundAfterForward = YES;
return grabber;
}
-(id)onMainAsync:(BOOL)async;
{
SPInvocationGrabber *grabber = [self grab];
grabber.onMainAfterForward = YES;
grabber.waitUntilDone = !async;
return grabber;
}
@end

View File

@@ -0,0 +1,28 @@
// A
+(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color;
{
float duration = 0.5;
UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease];
flash.backgroundColor = color;
[parent addSubview:flash];
[[flash invokeAfter:duration+0.1] removeFromSuperview];
[UIView beginAnimations:@"SPFlash" context:NULL];
[UIView setAnimationDuration:duration];
flash.alpha = 0.0;
[UIView commitAnimations];
return flash;
}
// B
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Force the animation to happen by calling this method again after a small
// delay - see http://blog.instapaper.com/post/53568356
[[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath];
}
// C
[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES];
[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];

View File

@@ -0,0 +1,12 @@
@interface MyClass : NSObject
-(BOOL)areTheNewViewersGoneYet:(Duck*)duck;
@end
...
MyClass *myInstance = [[MyClass alloc] init];
id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease];
[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9
NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation];

View File

@@ -0,0 +1,38 @@
#import <Cocoa/Cocoa.h>
#import "NSObject+SPInvocationGrabbing.h"
@interface Foo : NSObject {
int a;
}
-(void)startIt;
-(void)theBackgroundStuff;
-(void)theForegroundStuff;
@end
@implementation Foo
-(void)startIt;
{
NSLog(@"Starting out on the main thread...");
a = 3;
[[self inBackground] theBackgroundStuff];
}
-(void)theBackgroundStuff;
{
NSLog(@"Woah, this is a background thread!");
a += 6;
[[self onMainAsync:YES] theForegroundStuff];
}
-(void)theForegroundStuff;
{
NSLog(@"Hey presto: %d", a);
}
@end
int main() {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
Foo *foo = [Foo new];
[foo startIt];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
[pool release];
return 0;
}

34
3rdparty/SPMediaKeyTap/SPMediaKeyTap.h vendored Normal file
View File

@@ -0,0 +1,34 @@
#include <Cocoa/Cocoa.h>
#import <IOKit/hidsystem/ev_keymap.h>
#import <Carbon/Carbon.h>
// http://overooped.com/post/2593597587/mediakeys
#define SPSystemDefinedEventMediaKeys 8
@interface SPMediaKeyTap : NSObject {
EventHandlerRef _app_switching_ref;
EventHandlerRef _app_terminating_ref;
CFMachPortRef _eventPort;
CFRunLoopSourceRef _eventPortSource;
CFRunLoopRef _tapThreadRL;
BOOL _shouldInterceptMediaKeyEvents;
id _delegate;
// The app that is frontmost in this list owns media keys
NSMutableArray *_mediaKeyAppList;
}
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
-(id)initWithDelegate:(id)delegate;
+(BOOL)usesGlobalMediaKeyTap;
-(void)startWatchingMediaKeys;
-(void)stopWatchingMediaKeys;
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
@end
@interface NSObject (SPMediaKeyTapDelegate)
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
@end
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;

300
3rdparty/SPMediaKeyTap/SPMediaKeyTap.m vendored Normal file
View File

@@ -0,0 +1,300 @@
// Copyright (c) 2010 Spotify AB
#import "SPMediaKeyTap.h"
#import "SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h" // https://gist.github.com/511181, in submodule
@interface SPMediaKeyTap ()
-(BOOL)shouldInterceptMediaKeyEvents;
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
-(void)startWatchingAppSwitching;
-(void)stopWatchingAppSwitching;
-(void)eventTapThread;
@end
static SPMediaKeyTap *singleton = nil;
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
// Inspired by http://gist.github.com/546311
@implementation SPMediaKeyTap
#pragma mark -
#pragma mark Setup and teardown
-(id)initWithDelegate:(id)delegate;
{
_delegate = delegate;
[self startWatchingAppSwitching];
singleton = self;
_mediaKeyAppList = [NSMutableArray new];
return self;
}
-(void)dealloc;
{
[self stopWatchingMediaKeys];
[self stopWatchingAppSwitching];
[_mediaKeyAppList release];
[super dealloc];
}
-(void)startWatchingAppSwitching;
{
// Listen to "app switched" event, so that we don't intercept media keys if we
// weren't the last "media key listening" app to be active
EventTypeSpec eventType = { kEventClassApplication, kEventAppFrontSwitched };
OSStatus err = InstallApplicationEventHandler(NewEventHandlerUPP(appSwitched), 1, &eventType, self, &_app_switching_ref);
assert(err == noErr);
eventType.eventKind = kEventAppTerminated;
err = InstallApplicationEventHandler(NewEventHandlerUPP(appTerminated), 1, &eventType, self, &_app_terminating_ref);
assert(err == noErr);
}
-(void)stopWatchingAppSwitching;
{
if(!_app_switching_ref) return;
RemoveEventHandler(_app_switching_ref);
_app_switching_ref = NULL;
}
-(void)startWatchingMediaKeys;{
[self setShouldInterceptMediaKeyEvents:YES];
// Add an event tap to intercept the system defined media key events
_eventPort = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(NX_SYSDEFINED),
tapEventCallback,
self);
assert(_eventPort != NULL);
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
assert(_eventPortSource != NULL);
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
[NSThread detachNewThreadSelector:@selector(eventTapThread) toTarget:self withObject:nil];
}
-(void)stopWatchingMediaKeys;
{
// TODO<nevyn>: Shut down thread, remove event tap port and source
}
#pragma mark -
#pragma mark Accessors
+(BOOL)usesGlobalMediaKeyTap
{
#ifdef _DEBUG
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
return NO;
#else
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
return floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
#endif
}
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
{
return [NSArray arrayWithObjects:
[[NSBundle mainBundle] bundleIdentifier], // your app
@"com.spotify.client",
@"com.apple.iTunes",
@"com.apple.QuickTimePlayerX",
@"com.apple.quicktimeplayer",
@"com.apple.iWork.Keynote",
@"com.apple.iPhoto",
@"org.videolan.vlc",
@"com.apple.Aperture",
@"com.plexsquared.Plex",
@"com.soundcloud.desktop",
@"com.macromedia.fireworks", // the tap messes up their mouse input
nil
];
}
-(BOOL)shouldInterceptMediaKeyEvents;
{
BOOL shouldIntercept = NO;
@synchronized(self) {
shouldIntercept = _shouldInterceptMediaKeyEvents;
}
return shouldIntercept;
}
-(void)pauseTapOnTapThread:(BOOL)yeahno;
{
CGEventTapEnable(self->_eventPort, yeahno);
}
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
{
BOOL oldSetting;
@synchronized(self) {
oldSetting = _shouldInterceptMediaKeyEvents;
_shouldInterceptMediaKeyEvents = newSetting;
}
if(_tapThreadRL && oldSetting != newSetting) {
id grab = [self grab];
[grab pauseTapOnTapThread:newSetting];
NSTimer *timer = [NSTimer timerWithTimeInterval:0 invocation:[grab invocation] repeats:NO];
CFRunLoopAddTimer(_tapThreadRL, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
}
}
#pragma mark
#pragma mark -
#pragma mark Event tap callbacks
// Note: method called on background thread
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
SPMediaKeyTap *self = refcon;
if(type == kCGEventTapDisabledByTimeout) {
NSLog(@"Media key event tap was disabled by timeout");
CGEventTapEnable(self->_eventPort, TRUE);
return event;
} else if(type == kCGEventTapDisabledByUserInput) {
// Was disabled manually by -[pauseTapOnTapThread]
return event;
}
NSEvent *nsEvent = nil;
@try {
nsEvent = [NSEvent eventWithCGEvent:event];
}
@catch (NSException * e) {
NSLog(@"Strange CGEventType: %d: %@", type, e);
assert(0);
return event;
}
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
return event;
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND)
return event;
if (![self shouldInterceptMediaKeyEvents])
return event;
[nsEvent retain]; // matched in handleAndReleaseMediaKeyEvent:
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
return NULL;
}
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
[pool drain];
return ret;
}
// event will have been retained in the other thread
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event {
[event autorelease];
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
}
-(void)eventTapThread;
{
_tapThreadRL = CFRunLoopGetCurrent();
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
CFRunLoopRun();
}
#pragma mark Task switching callbacks
NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys";
-(void)mediaKeyAppListChanged;
{
if([_mediaKeyAppList count] == 0) return;
/*NSLog(@"--");
int i = 0;
for (NSValue *psnv in _mediaKeyAppList) {
ProcessSerialNumber psn; [psnv getValue:&psn];
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
&psn,
kProcessDictionaryIncludeAllInformationMask
) autorelease];
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
NSLog(@"%d: %@", i++, bundleIdentifier);
}*/
ProcessSerialNumber mySerial, topSerial;
GetCurrentProcess(&mySerial);
[[_mediaKeyAppList objectAtIndex:0] getValue:&topSerial];
Boolean same;
OSErr err = SameProcess(&mySerial, &topSerial, &same);
[self setShouldInterceptMediaKeyEvents:(err == noErr && same)];
}
-(void)appIsNowFrontmost:(ProcessSerialNumber)psn;
{
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
&psn,
kProcessDictionaryIncludeAllInformationMask
) autorelease];
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
NSArray *whitelistIdentifiers = [[NSUserDefaults standardUserDefaults] arrayForKey:kMediaKeyUsingBundleIdentifiersDefaultsKey];
if(![whitelistIdentifiers containsObject:bundleIdentifier]) return;
[_mediaKeyAppList removeObject:psnv];
[_mediaKeyAppList insertObject:psnv atIndex:0];
[self mediaKeyAppListChanged];
}
-(void)appTerminated:(ProcessSerialNumber)psn;
{
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
[_mediaKeyAppList removeObject:psnv];
[self mediaKeyAppListChanged];
}
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
{
SPMediaKeyTap *self = (id)userData;
ProcessSerialNumber newSerial;
GetFrontProcess(&newSerial);
[self appIsNowFrontmost:newSerial];
return CallNextEventHandler(nextHandler, evt);
}
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
{
SPMediaKeyTap *self = (id)userData;
ProcessSerialNumber deadPSN;
GetEventParameter(
evt,
kEventParamProcessID,
typeProcessSerialNumber,
NULL,
sizeof(deadPSN),
NULL,
&deadPSN
);
[self appTerminated:deadPSN];
return CallNextEventHandler(nextHandler, evt);
}
@end

View File

@@ -0,0 +1,25 @@
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
{
assert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys);
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
int keyFlags = ([event data1] & 0x0000FFFF);
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
int keyRepeat = (keyFlags & 0x1);
if (keyState == 1 && windowController != NULL) {
switch (keyCode) {
case NX_KEYTYPE_PLAY:
... return;
case NX_KEYTYPE_FAST:
... return;
case NX_KEYTYPE_REWIND:
... return;
}
}
}

View File

@@ -24,6 +24,7 @@ else()
qprogressindicatorspinning_nonmac.cpp
)
set(RESOURCES
qsearchfield_nonmac.qrc
qprogressindicatorspinning_nonmac.qrc
)
qt5_add_resources(RESOURCES_SOURCES ${RESOURCES})
@@ -31,3 +32,4 @@ endif()
add_library(Qocoa STATIC ${SOURCES} ${MOC_SOURCES} ${RESOURCES_SOURCES})
target_link_libraries(Qocoa ${QT_LIBRARIES})

View File

@@ -1,17 +0,0 @@
SOURCES += main.cpp\
gallery.cpp \
HEADERS += gallery.h \
qocoa_mac.h \
qsearchfield.h \
qbutton.h \
qprogressindicatorspinning.h \
mac {
OBJECTIVE_SOURCES += qsearchfield_mac.mm qbutton_mac.mm qprogressindicatorspinning_mac.mm
LIBS += -framework Foundation -framework Appkit
QMAKE_CFLAGS += -mmacosx-version-min=10.6
} else {
SOURCES += qsearchfield_nonmac.cpp qbutton_nonmac.cpp qprogressindicatorspinning_nonmac.cpp
RESOURCES += qsearchfield_nonmac.qrc qprogressindicatorspinning_nonmac.qrc
}

View File

@@ -16,7 +16,9 @@ make
```
## Status
Qocoa classes are currently provided for NSButton, a spinning NSProgressIndicator and NSSearchField. There is a [TODO list](https://github.com/mikemcquaid/Qocoa/blob/master/TODO.md) for classes I hope to implement.
I'm not personally working on this any more but will accept pull-requests.
[![Build Status](https://travis-ci.org/MikeMcQuaid/Qocoa.svg?branch=master)](https://travis-ci.org/MikeMcQuaid/Qocoa)
## Usage
For each class you want to use copy the [`qocoa_mac.h`](https://github.com/mikemcquaid/Qocoa/blob/master/qocoa_mac.h), `$CLASS.h`, `$CLASS_mac.*` and `$CLASS_nonmac.*` files into your source tree and add them to your buildsystem. Examples are provided for [CMake](https://github.com/mikemcquaid/Qocoa/blob/master/CMakeLists.txt) and [QMake](https://github.com/mikemcquaid/Qocoa/blob/master/Qocoa.pro).
@@ -28,7 +30,9 @@ For each class you want to use copy the [`qocoa_mac.h`](https://github.com/mikem
Qocoa is licensed under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
The full license text is available in [LICENSE.txt](https://github.com/mikemcquaid/Qocoa/blob/master/LICENSE.txt).
The icons are taken from the [Oxygen Project](http://www.oxygen-icons.org/) and are licensed under the [Creative Commons Attribution-ShareAlike 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/).
Magnifier and EditClear icons taken from [QtCreator](http://qt-project.org/) and are licensed under the [LGPL](http://www.gnu.org/copyleft/lesser.html).
Other icons are taken from the [Oxygen Project](http://www.oxygen-icons.org/) and are licensed under the [Creative Commons Attribution-ShareAlike 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/).
## Gallery
![Qocoa Gallery](https://github.com/mikemcquaid/Qocoa/raw/master/gallery.png)

View File

@@ -1,70 +0,0 @@
#include "gallery.h"
#include <QVBoxLayout>
#include "qsearchfield.h"
#include "qbutton.h"
#include "qprogressindicatorspinning.h"
Gallery::Gallery(QWidget *parent) : QWidget(parent)
{
setWindowTitle("Qocoa Gallery");
QVBoxLayout *layout = new QVBoxLayout(this);
QSearchField *searchField = new QSearchField(this);
layout->addWidget(searchField);
QButton *roundedButton = new QButton(this, QButton::Rounded);
roundedButton->setText("Button");
layout->addWidget(roundedButton);
QButton *regularSquareButton = new QButton(this, QButton::RegularSquare);
regularSquareButton->setText("Button");
layout->addWidget(regularSquareButton);
QButton *disclosureButton = new QButton(this, QButton::Disclosure);
layout->addWidget(disclosureButton);
QButton *shadowlessSquareButton = new QButton(this, QButton::ShadowlessSquare);
shadowlessSquareButton->setText("Button");
layout->addWidget(shadowlessSquareButton);
QButton *circularButton = new QButton(this, QButton::Circular);
layout->addWidget(circularButton);
QButton *textureSquareButton = new QButton(this, QButton::TexturedSquare);
textureSquareButton->setText("Textured Button");
layout->addWidget(textureSquareButton);
QButton *helpButton = new QButton(this, QButton::HelpButton);
layout->addWidget(helpButton);
QButton *smallSquareButton = new QButton(this, QButton::SmallSquare);
smallSquareButton->setText("Gradient Button");
layout->addWidget(smallSquareButton);
QButton *texturedRoundedButton = new QButton(this, QButton::TexturedRounded);
texturedRoundedButton->setText("Round Textured");
layout->addWidget(texturedRoundedButton);
QButton *roundedRectangleButton = new QButton(this, QButton::RoundRect);
roundedRectangleButton->setText("Rounded Rect Button");
layout->addWidget(roundedRectangleButton);
QButton *recessedButton = new QButton(this, QButton::Recessed);
recessedButton->setText("Recessed Button");
layout->addWidget(recessedButton);
QButton *roundedDisclosureButton = new QButton(this, QButton::RoundedDisclosure);
layout->addWidget(roundedDisclosureButton);
#ifdef MAC_OS_X_VERSION_10_7
QButton *inlineButton = new QButton(this, QButton::Inline);
inlineButton->setText("Inline Button");
layout->addWidget(inlineButton);
#endif
QProgressIndicatorSpinning *progressIndicatorSpinning = new QProgressIndicatorSpinning(this);
progressIndicatorSpinning->animate();
layout->addWidget(progressIndicatorSpinning);
}

View File

@@ -1,14 +0,0 @@
#ifndef GALLERY_H
#define GALLERY_H
#include <QWidget>
class Gallery : public QWidget
{
Q_OBJECT
public:
explicit Gallery(QWidget *parent = 0);
};
#endif // WIDGET_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1,12 +0,0 @@
#include <QApplication>
#include "gallery.h"
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Gallery gallery;
gallery.show();
return application.exec();
}

View File

@@ -3,7 +3,6 @@
#include <QWidget>
#include <QPointer>
#include <QString>
class QButtonPrivate;
class QButton : public QWidget
@@ -24,7 +23,7 @@ public:
RoundRect = 12,
Recessed = 13,
RoundedDisclosure = 14,
#ifdef MAC_OS_X_VERSION_10_7
#ifdef __MAC_10_7
Inline = 15
#endif
};

View File

@@ -37,7 +37,9 @@ public:
switch(bezelStyle) {
case QButton::Disclosure:
case QButton::Circular:
#ifdef __MAC_10_7
case QButton::Inline:
#endif
case QButton::RoundedDisclosure:
case QButton::HelpButton:
[nsButton setTitle:@""];
@@ -55,7 +57,7 @@ public:
font = [NSFont fontWithName:@"Lucida Grande Bold" size:12];
break;
#ifdef MAC_OS_X_VERSION_10_7
#ifdef __MAC_10_7
case QButton::Inline:
font = [NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
break;
@@ -112,7 +114,7 @@ public:
qButton->setFixedHeight(22);
qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
break;
#ifdef MAC_OS_X_VERSION_10_7
#ifdef __MAC_10_7
case QButton::Inline:
qButton->setMinimumWidth(10);
qButton->setFixedHeight(16);
@@ -130,7 +132,7 @@ public:
[nsButton setButtonType:NSMomentaryPushInButton];
}
[nsButton setBezelStyle:bezelStyle];
[nsButton setBezelStyle:(__bridge NSBezelStyle)bezelStyle];
}
void clicked()

View File

@@ -20,19 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QPointer>
#include <QString>
#include <QPixmap>
#include <QAbstractButton>
#include <QBoxLayout>
#include <QPushButton>
#include "qbutton.h"
#include <QToolBar>
#include <QToolButton>
#include "qbutton.h"
#include <QPushButton>
#include <QVBoxLayout>
class QButtonPrivate : public QObject
{

View File

@@ -20,10 +20,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <AppKit/NSImage.h>
#include <Foundation/NSString.h>
#include <QByteArray>
#include <QString>
#include <QBoxLayout>
#include <QtMacExtras>
#include <QMacCocoaViewContainer>
static inline NSString* fromQString(const QString &string)
@@ -42,11 +43,11 @@ static inline QString toQString(NSString *string)
static inline NSImage* fromQPixmap(const QPixmap &pixmap)
{
CGImageRef cgImage = pixmap.toMacCGImageRef();
CGImageRef cgImage = QtMac::toCGImageRef(pixmap);
return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];
}
static inline void setupLayout(void *cocoaView, QWidget *parent)
static inline void setupLayout(NSView *cocoaView, QWidget *parent)
{
parent->setAttribute(Qt::WA_NativeWindow);
QVBoxLayout *layout = new QVBoxLayout(parent);

View File

@@ -17,7 +17,8 @@ public:
Aqua = 12
};
explicit QProgressIndicatorSpinning(QWidget *parent, Thickness thickness = Default);
explicit QProgressIndicatorSpinning(QWidget *parent,
Thickness thickness = Default);
public slots:
void animate(bool animate = true);
private:

View File

@@ -20,17 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QBoxLayout>
#include <QLabel>
#include <QMovie>
#include <QPointer>
#include <QSize>
#include "qprogressindicatorspinning.h"
#include <QVBoxLayout>
#include <QMovie>
#include <QLabel>
class QProgressIndicatorSpinningPrivate : public QObject
{
public:

View File

@@ -2,44 +2,42 @@
#define QSEARCHFIELD_H
#include <QWidget>
#include <QObject>
#include <QPointer>
#include <QString>
#include <QEvent>
#include <QResizeEvent>
#include <QMenu>
class QSearchFieldPrivate;
class QSearchField : public QWidget
{
Q_OBJECT
public:
explicit QSearchField(QWidget *parent);
class QSearchField : public QWidget {
Q_OBJECT
QString text() const;
QString placeholderText() const;
void setFocus(Qt::FocusReason reason);
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true);
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
public:
explicit QSearchField(QWidget *parent);
QString text() const;
QString placeholderText() const;
void setFocus(Qt::FocusReason);
public slots:
void setText(const QString &text);
void setPlaceholderText(const QString &text);
void clear();
void selectAll();
void setFocus();
void setText(const QString &text);
void setPlaceholderText(const QString &text);
void clear();
void selectAll();
void setFocus();
signals:
void textChanged(const QString &text);
void editingFinished();
void returnPressed();
void textChanged(const QString &text);
void editingFinished();
void returnPressed();
protected:
void resizeEvent(QResizeEvent*);
bool eventFilter(QObject*, QEvent*);
void resizeEvent(QResizeEvent*);
bool eventFilter(QObject*, QEvent*);
private:
friend class QSearchFieldPrivate;
QPointer <QSearchFieldPrivate> pimpl;
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
friend class QSearchFieldPrivate;
QPointer <QSearchFieldPrivate> pimpl;
};
#endif // QSEARCHFIELD_H

View File

@@ -29,60 +29,53 @@ THE SOFTWARE.
#import "AppKit/NSSearchField.h"
#include <QApplication>
#include <QClipboard>
#include <QKeyEvent>
#include <QClipboard>
class QSearchFieldPrivate : public QObject
{
class QSearchFieldPrivate : public QObject {
public:
QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField)
: QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {}
QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField)
: QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {}
void textDidChange(const QString &text)
{
if (qSearchField)
emit qSearchField->textChanged(text);
void textDidChange(const QString &text) {
if (qSearchField) emit qSearchField->textChanged(text);
}
void textDidEndEditing() {
if (qSearchField)
emit qSearchField->editingFinished();
}
void textDidEndEditing()
{
if (qSearchField)
emit qSearchField->editingFinished();
void returnPressed() {
if (qSearchField) {
emit qSearchField->returnPressed();
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void returnPressed()
{
if (qSearchField) {
emit qSearchField->returnPressed();
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
void keyDownPressed() {
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void keyDownPressed()
{
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
void keyUpPressed() {
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void keyUpPressed()
{
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
QPointer<QSearchField> qSearchField;
NSSearchField *nsSearchField;
QPointer<QSearchField> qSearchField;
NSSearchField *nsSearchField;
};
@interface QSearchFieldDelegate : NSObject<NSTextFieldDelegate>
{
@interface QSearchFieldDelegate : NSObject<NSTextFieldDelegate> {
@public
QPointer<QSearchFieldPrivate> pimpl;
QPointer<QSearchFieldPrivate> pimpl;
}
-(void)controlTextDidChange:(NSNotification*)notification;
-(void)controlTextDidEndEditing:(NSNotification*)notification;
@@ -90,35 +83,33 @@ public:
@implementation QSearchFieldDelegate
-(void)controlTextDidChange:(NSNotification*)notification {
Q_ASSERT(pimpl);
if (pimpl)
pimpl->textDidChange(toQString([[notification object] stringValue]));
}
-(BOOL)control: (NSControl *)control textView:
(NSTextView *)textView doCommandBySelector:
(SEL)commandSelector {
Q_ASSERT(pimpl);
if (!pimpl) return NO;
if (commandSelector == @selector(moveDown:)) {
pimpl->keyDownPressed();
return YES;
} else if (commandSelector == @selector(moveUp:)) {
pimpl->keyUpPressed();
return YES;
}
return NO;
Q_ASSERT(pimpl);
if (pimpl) pimpl->textDidChange(toQString([[notification object] stringValue]));
}
-(void)controlTextDidEndEditing:(NSNotification*)notification {
// No Q_ASSERT here as it is called on destruction.
if (!pimpl) return;
Q_UNUSED(notification);
// No Q_ASSERT here as it is called on destruction.
if (!pimpl) return;
pimpl->textDidEndEditing();
if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
pimpl->returnPressed();
}
pimpl->textDidEndEditing();
if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
pimpl->returnPressed();
-(BOOL)control: (NSControl *)control textView:
(NSTextView *)textView doCommandBySelector:
(SEL)commandSelector {
Q_ASSERT(pimpl);
if (!pimpl) return NO;
if (commandSelector == @selector(moveDown:)) {
pimpl->keyDownPressed();
return YES;
}
else if (commandSelector == @selector(moveUp:)) {
pimpl->keyUpPressed();
return YES;
}
return NO;
}
@end
@@ -129,157 +120,109 @@ public:
@implementation QocoaSearchField
-(BOOL)performKeyEquivalent:(NSEvent*)event {
// First, check if we have the focus.
// If no, it probably means this event isn't for us.
NSResponder* firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] && [(NSText*)firstResponder delegate] == self) {
// First, check if we have the focus.
// If no, it probably means this event isn't for us.
NSResponder* firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] &&
[(NSText*)firstResponder delegate] == self) {
if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask)
{
QString keyString = toQString([event characters]);
if (keyString == "a") // Cmd+a
{
[self performSelector:@selector(selectText:)];
return YES;
}
else if (keyString == "c") // Cmd+c
{
[[self currentEditor] copy: nil];
return YES;
}
else if (keyString == "v") // Cmd+v
{
[[self currentEditor] paste: nil];
return YES;
}
else if (keyString == "x") // Cmd+x
{
[[self currentEditor] cut: nil];
return YES;
}
}
if ([event type] == NSEventTypeKeyDown && [event modifierFlags] & NSEventModifierFlagCommand) {
QString keyString = toQString([event characters]);
if (keyString == "a") // Cmd+a
{
[self performSelector:@selector(selectText:)];
return YES;
}
else if (keyString == "c") // Cmd+c
{
[[self currentEditor] copy: nil];
return YES;
}
else if (keyString == "v") // Cmd+v
{
[[self currentEditor] paste: nil];
return YES;
}
else if (keyString == "x") // Cmd+x
{
[[self currentEditor] cut: nil];
return YES;
}
}
}
return NO;
return NO;
}
@end
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSearchField *search = [[QocoaSearchField alloc] init];
QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
[search setDelegate:delegate];
setupLayout(search, this);
setFixedHeight(24);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
[search release];
[pool drain];
QSearchField::QSearchField(QWidget *parent) : QWidget(parent) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSearchField *search = [[QocoaSearchField alloc] init];
QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
[search setDelegate:delegate];
setupLayout(search, this);
setFixedHeight(24);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
[search release];
[pool drain];
}
void QSearchField::setText(const QString &text)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
void QSearchField::setText(const QString &text) {
Q_ASSERT(pimpl);
if (!pimpl) return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pimpl->nsSearchField setStringValue:fromQString(text)];
if (!text.isEmpty()) {
[pimpl->nsSearchField selectText:pimpl->nsSearchField];
[[pimpl->nsSearchField currentEditor] setSelectedRange:NSMakeRange([[pimpl->nsSearchField stringValue] length], 0)];
}
[pool drain];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pimpl->nsSearchField setStringValue:fromQString(text)];
if (!text.isEmpty()) {
[pimpl->nsSearchField selectText:pimpl->nsSearchField];
[[pimpl->nsSearchField currentEditor] setSelectedRange:NSMakeRange([[pimpl->nsSearchField stringValue] length], 0)];
}
[pool drain];
}
void QSearchField::setPlaceholderText(const QString &text)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
void QSearchField::setPlaceholderText(const QString &text) {
Q_ASSERT(pimpl);
if (!pimpl) return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)];
[pool drain];
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)];
[pool drain];
void QSearchField::clear() {
Q_ASSERT(pimpl);
if (!pimpl) return;
[pimpl->nsSearchField setStringValue:@""];
emit textChanged(QString());
}
void QSearchField::selectAll() {
Q_ASSERT(pimpl);
if (!pimpl) return;
[pimpl->nsSearchField performSelector:@selector(selectText:)];
}
QString QSearchField::text() const {
Q_ASSERT(pimpl);
if (!pimpl) return QString();
return toQString([pimpl->nsSearchField stringValue]);
}
QString QSearchField::placeholderText() const {
Q_ASSERT(pimpl);
NSString* placeholder = [[pimpl->nsSearchField cell] placeholderString];
return toQString(placeholder);
Q_ASSERT(pimpl);
return toQString([[pimpl->nsSearchField cell] placeholderString]);
}
void QSearchField::setFocus(Qt::FocusReason reason)
{
/* Do nothing: we were previously using makeFirstResponder on search field, but
* that resulted in having the text being selected (and I didn't find any way to
* deselect it) which would result in the user erasing the first letter he just
* typed, after using setText (e.g. if the user typed a letter while having
* focus on the playlist, which means we call setText and give focus to the
* search bar).
* Instead now the focus will take place when calling selectText in setText.
* This obviously breaks the purpose of this function, but we never call only
* setFocus on a search box in Clementine (i.e. without a call to setText
* shortly after).
*/
void QSearchField::setFocus(Qt::FocusReason) {}
// Q_ASSERT(pimpl);
// if (!pimpl)
// return;
// if ([pimpl->nsSearchField acceptsFirstResponder]) {
// [[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField];
// }
void QSearchField::setFocus() {
setFocus(Qt::OtherFocusReason);
}
void QSearchField::setFocus()
{
setFocus(Qt::OtherFocusReason);
void QSearchField::resizeEvent(QResizeEvent *resizeEvent) {
QWidget::resizeEvent(resizeEvent);
}
void QSearchField::clear()
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
[pimpl->nsSearchField setStringValue:@""];
emit textChanged(QString());
bool QSearchField::eventFilter(QObject *o, QEvent *e) {
return QWidget::eventFilter(o, e);
}
void QSearchField::selectAll()
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
[pimpl->nsSearchField performSelector:@selector(selectText:)];
}
QString QSearchField::text() const
{
Q_ASSERT(pimpl);
if (!pimpl)
return QString();
return toQString([pimpl->nsSearchField stringValue]);
}
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
QWidget::resizeEvent(resizeEvent);
}
bool QSearchField::eventFilter(QObject *o, QEvent *e)
{
return QWidget::eventFilter(o, e);
}

View File

@@ -20,169 +20,142 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QPointer>
#include <QString>
#include <QIcon>
#include <QSize>
#include <QStyle>
#include <QLineEdit>
#include <QBoxLayout>
#include <QToolButton>
#include <QtEvents>
#include "../../src/core/iconloader.h"
#include "qsearchfield.h"
class QSearchFieldPrivate : public QObject
{
#include <QApplication>
#include <QDesktopWidget>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QToolButton>
#include <QStyle>
#include <QEvent>
#include <QDir>
#include <QDebug>
#include "../../src/core/iconloader.h"
class QSearchFieldPrivate : public QObject {
public:
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
int lineEditFrameWidth() const {
return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
}
int clearButtonPaddedWidth() const {
return clearButton->width() + lineEditFrameWidth() * 2;
}
int clearButtonPaddedHeight() const {
return clearButton->height() + lineEditFrameWidth() * 2;
}
QPointer<QLineEdit> lineEdit;
QPointer<QToolButton> clearButton;
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
int lineEditFrameWidth() const {
return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
}
int clearButtonPaddedWidth() const {
return clearButton->width() + lineEditFrameWidth() * 2;
}
int clearButtonPaddedHeight() const {
return clearButton->height() + lineEditFrameWidth() * 2;
}
QPointer<QLineEdit> lineEdit;
QPointer<QToolButton> clearButton;
};
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
QLineEdit *lineEdit = new QLineEdit(this);
connect(lineEdit, SIGNAL(textChanged(QString)),
this, SIGNAL(textChanged(QString)));
connect(lineEdit, SIGNAL(editingFinished()),
this, SIGNAL(editingFinished()));
connect(lineEdit, SIGNAL(returnPressed()),
this, SIGNAL(returnPressed()));
connect(lineEdit, SIGNAL(textChanged(QString)),
this, SLOT(setText(QString)));
QSearchField::QSearchField(QWidget *parent) : QWidget(parent) {
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
QLineEdit *lineEdit = new QLineEdit(this);
connect(lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
connect(lineEdit, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
connect(lineEdit, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()));
connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(setText(QString)));
QToolButton *clearButton = new QToolButton(this);
clearButton->setIcon(clearIcon);
clearButton->setIconSize(QSize(16, 16));
clearButton->setStyleSheet("border: none; padding: 0px;");
clearButton->resize(clearButton->sizeHint());
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
QToolButton *clearButton = new QToolButton(this);
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
clearButton->setIcon(clearIcon);
clearButton->setIconSize(QSize(16, 16));
clearButton->setStyleSheet("border: none; padding: 0px;");
clearButton->resize(clearButton->sizeHint());
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(clearButton->width()));
const int width = frame_width + qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
const int height = frame_width + qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
lineEdit->setMinimumSize(width, height);
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(lineEdit);
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(clearButton->width()));
const int width = frame_width + qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
const int height = frame_width + qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
lineEdit->setMinimumSize(width, height);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(lineEdit);
lineEdit->installEventFilter(this);
lineEdit->installEventFilter(this);
}
void QSearchField::setText(const QString &text)
{
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
return;
void QSearchField::setText(const QString &text) {
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
if (text != this->text()) pimpl->lineEdit->setText(text);
if (text != this->text())
pimpl->lineEdit->setText(text);
}
void QSearchField::setPlaceholderText(const QString &text)
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
#if QT_VERSION >= 0x040700
pimpl->lineEdit->setPlaceholderText(text);
#endif
void QSearchField::setPlaceholderText(const QString &text) {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->setPlaceholderText(text);
}
QString QSearchField::placeholderText() const {
#if QT_VERSION >= 0x040700
return pimpl->lineEdit->placeholderText();
#else
return QString();
#endif
}
void QSearchField::setFocus(Qt::FocusReason reason)
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (pimpl && pimpl->lineEdit)
pimpl->lineEdit->setFocus(reason);
void QSearchField::setFocus(Qt::FocusReason reason) {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (pimpl && pimpl->lineEdit) pimpl->lineEdit->setFocus(reason);
}
void QSearchField::setFocus()
{
setFocus(Qt::OtherFocusReason);
void QSearchField::setFocus() {
setFocus(Qt::OtherFocusReason);
}
void QSearchField::clear()
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
pimpl->lineEdit->clear();
void QSearchField::clear() {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->clear();
}
void QSearchField::selectAll()
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
pimpl->lineEdit->selectAll();
void QSearchField::selectAll() {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->selectAll();
}
QString QSearchField::text() const
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return QString();
return pimpl->lineEdit->text();
QString QSearchField::text() const {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return QString();
return pimpl->lineEdit->text();
}
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
return;
void QSearchField::resizeEvent(QResizeEvent *resizeEvent) {
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
QWidget::resizeEvent(resizeEvent);
const int x = pimpl->lineEditFrameWidth();
const int y = (height() - pimpl->clearButton->height())/2;
pimpl->clearButton->move(x, y);
QWidget::resizeEvent(resizeEvent);
const int x = pimpl->lineEditFrameWidth();
const int y = (height() - pimpl->clearButton->height())/2;
pimpl->clearButton->move(x, y);
}
bool QSearchField::eventFilter(QObject *o, QEvent *e)
{
if (pimpl && pimpl->lineEdit && o == pimpl->lineEdit) {
// Forward some lineEdit events to QSearchField (only those we need for
// now, but some might be added later if needed)
switch (e->type()) {
case QEvent::FocusIn:
case QEvent::FocusOut:
QApplication::sendEvent(this, e);
break;
}
bool QSearchField::eventFilter(QObject *o, QEvent *e) {
if (pimpl && pimpl->lineEdit && o == pimpl->lineEdit) {
// Forward some lineEdit events to QSearchField (only those we need for
// now, but some might be added later if needed)
switch (e->type()) {
case QEvent::FocusIn:
case QEvent::FocusOut:
QApplication::sendEvent(this, e);
break;
}
return QWidget::eventFilter(o, e);
}
return QWidget::eventFilter(o, e);
}

View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/Qocoa">
<file>qsearchfield_nonmac_clear.png</file>
<file>qsearchfield_nonmac_magnifier_menu.png</file>
<file>qsearchfield_nonmac_magnifier.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

View File

@@ -27,3 +27,5 @@ ADD_LIBRARY(qtsingleapplication STATIC
)
target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network)
include_directories(${CMAKE_BINARY_DIR}/src)

View File

@@ -45,7 +45,7 @@
#include <QVector>
#endif
#if defined(Q_WS_WIN) || defined(Q_OS_WIN)
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)

View File

@@ -37,6 +37,7 @@
**
****************************************************************************/
#include "config.h"
#include "qtsingleapplication.h"
@@ -44,6 +45,10 @@
#include <QWidget>
#include <QString>
#ifdef HAVE_X11_ // FIXME
# include <X11/Xlib.h>
#endif
#include "qtlocalpeer.h"
/*!
@@ -173,14 +178,14 @@ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char *
}
#if defined(Q_WS_X11)
#if defined(HAVE_X11_) // FIXME
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
QtSingleApplication::QtSingleApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap)
{
sysInit();
@@ -206,7 +211,7 @@ QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Q
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
QtSingleApplication::QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit(appId);

View File

@@ -40,14 +40,21 @@
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QString>
#if defined(HAVE_X11_) // FIXME
# include <X11/Xlib.h>
#endif
class QtLocalPeer;
#if defined(Q_WS_WIN) || defined(Q_OS_WIN32)
#if defined(Q_OS_WIN) || defined(Q_OS_WIN32)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
@@ -70,10 +77,10 @@ class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
#if defined(HAVE_X11_) // FIXME
QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
#endif
bool isRunning();

View File

@@ -40,6 +40,8 @@
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include "config.h"
#include <QCoreApplication>
#include <QObject>
#include <QString>

View File

@@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 11)
set(QTWIN-SOURCES
qtwin.cpp
)
ADD_LIBRARY(qtwin STATIC
${QTWIN-SOURCES}
)
target_link_libraries(qtwin
Qt5::Widgets
)

View File

@@ -1,229 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#include "qtwin.h"
#include <QLibrary>
#include <QApplication>
#include <QWidget>
#include <QList>
#include <QPointer>
#ifdef Q_WS_WIN
#include <qt_windows.h>
// Blur behind data structures
#define DWM_BB_ENABLE 0x00000001 // fEnable has been specified
#define DWM_BB_BLURREGION 0x00000002 // hRgnBlur has been specified
#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 // fTransitionOnMaximized has been specified
#define WM_DWMCOMPOSITIONCHANGED 0x031E // Composition changed window message
typedef struct _DWM_BLURBEHIND
{
DWORD dwFlags;
BOOL fEnable;
HRGN hRgnBlur;
BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND, *PDWM_BLURBEHIND;
typedef struct _MARGINS
{
int cxLeftWidth;
int cxRightWidth;
int cyTopHeight;
int cyBottomHeight;
} MARGINS, *PMARGINS;
typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
typedef HRESULT (WINAPI *PtrDwmGetColorizationColor)(DWORD *pcrColorization, BOOL *pfOpaqueBlend);
static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled= 0;
static PtrDwmEnableBlurBehindWindow pDwmEnableBlurBehindWindow = 0;
static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
static PtrDwmGetColorizationColor pDwmGetColorizationColor = 0;
/*
* Internal helper class that notifies windows if the
* DWM compositing state changes and updates the widget
* flags correspondingly.
*/
class WindowNotifier : public QWidget
{
public:
WindowNotifier() { winId(); }
void addWidget(QWidget *widget) { widgets.append(widget); }
void removeWidget(QWidget *widget) { widgets.removeAll(widget); }
bool winEvent(MSG *message, long *result);
private:
QWidgetList widgets;
};
static bool resolveLibs()
{
if (!pDwmIsCompositionEnabled) {
QLibrary dwmLib(QString::fromAscii("dwmapi"));
pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow");
pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib.resolve("DwmGetColorizationColor");
}
return pDwmIsCompositionEnabled != 0;
}
#endif
/*!
* Chekcs and returns true if Windows DWM composition
* is currently enabled on the system.
*
* To get live notification on the availability of
* this feature, you will currently have to
* reimplement winEvent() on your widget and listen
* for the WM_DWMCOMPOSITIONCHANGED event to occur.
*
*/
bool QtWin::isCompositionEnabled()
{
#ifdef Q_WS_WIN
if (resolveLibs()) {
HRESULT hr = S_OK;
BOOL isEnabled = false;
hr = pDwmIsCompositionEnabled(&isEnabled);
if (SUCCEEDED(hr))
return isEnabled;
}
#endif
return false;
}
/*!
* Enables Blur behind on a Widget.
*
* \a enable tells if the blur should be enabled or not
*/
bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable,
const QRegion &region)
{
Q_ASSERT(widget);
bool result = false;
#ifdef Q_WS_WIN
if (resolveLibs()) {
DWM_BLURBEHIND bb = {0};
HRESULT hr = S_OK;
bb.fEnable = enable;
bb.dwFlags = DWM_BB_ENABLE;
bb.hRgnBlur = NULL;
if (!region.isEmpty()) {
bb.dwFlags |= DWM_BB_BLURREGION;
bb.hRgnBlur = region.handle();
}
widget->setAttribute(Qt::WA_TranslucentBackground, enable);
widget->setAttribute(Qt::WA_NoSystemBackground, enable);
hr = pDwmEnableBlurBehindWindow(widget->winId(), &bb);
if (SUCCEEDED(hr)) {
result = true;
windowNotifier()->addWidget(widget);
}
}
#endif
return result;
}
/*!
* ExtendFrameIntoClientArea.
*
* This controls the rendering of the frame inside the window.
* Note that passing margins of -1 (the default value) will completely
* remove the frame from the window.
*
* \note you should not call enableBlurBehindWindow before calling
* this functions
*
* \a enable tells if the blur should be enabled or not
*/
bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int right, int bottom)
{
Q_ASSERT(widget);
Q_UNUSED(left);
Q_UNUSED(top);
Q_UNUSED(right);
Q_UNUSED(bottom);
bool result = false;
#ifdef Q_WS_WIN
if (resolveLibs()) {
QLibrary dwmLib(QString::fromAscii("dwmapi"));
HRESULT hr = S_OK;
MARGINS m = {left, top, right, bottom};
hr = pDwmExtendFrameIntoClientArea(widget->winId(), &m);
if (SUCCEEDED(hr)) {
result = true;
windowNotifier()->addWidget(widget);
}
widget->setAttribute(Qt::WA_TranslucentBackground, result);
}
#endif
return result;
}
/*!
* Returns the current colorizationColor for the window.
*
* \a enable tells if the blur should be enabled or not
*/
QColor QtWin::colorizatinColor()
{
QColor resultColor = QApplication::palette().window().color();
#ifdef Q_WS_WIN
if (resolveLibs()) {
DWORD color = 0;
BOOL opaque = FALSE;
QLibrary dwmLib(QString::fromAscii("dwmapi"));
HRESULT hr = S_OK;
hr = pDwmGetColorizationColor(&color, &opaque);
if (SUCCEEDED(hr))
resultColor = QColor(color);
}
#endif
return resultColor;
}
#ifdef Q_WS_WIN
WindowNotifier *QtWin::windowNotifier()
{
static WindowNotifier *windowNotifierInstance = 0;
if (!windowNotifierInstance)
windowNotifierInstance = new WindowNotifier;
return windowNotifierInstance;
}
/* Notify all enabled windows that the DWM state changed */
bool WindowNotifier::winEvent(MSG *message, long *result)
{
if (message && message->message == WM_DWMCOMPOSITIONCHANGED) {
bool compositionEnabled = QtWin::isCompositionEnabled();
foreach(QWidget * widget, widgets) {
if (widget) {
widget->setAttribute(Qt::WA_NoSystemBackground, compositionEnabled);
}
widget->update();
}
}
return QWidget::winEvent(message, result);
}
#endif

View File

@@ -1,38 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#ifndef QTWIN_H
#define QTWIN_H
#include <QColor>
#include <QWidget>
/**
* This is a helper class for using the Desktop Window Manager
* functionality on Windows 7 and Windows Vista. On other platforms
* these functions will simply not do anything.
*/
class WindowNotifier;
class QtWin
{
public:
static bool enableBlurBehindWindow(QWidget *widget, bool enable = true,
const QRegion& region = QRegion());
static bool extendFrameIntoClientArea(QWidget *widget,
int left = -1, int top = -1,
int right = -1, int bottom = -1);
static bool isCompositionEnabled();
static QColor colorizatinColor();
private:
static WindowNotifier *windowNotifier();
};
#endif // QTWIN_H

View File

@@ -1,6 +1,14 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 11)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if (NOT WIN32 AND NOT APPLE)
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
message(FATAL_ERROR "Missing qpa/qplatformnativeinterface.h, check that you got the QT private headers installed (package libQt5Gui-private-headers-devel, qtbase5-private-dev or similar)")
endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
endif(NOT WIN32 AND NOT APPLE)
set(QXT-SOURCES
qxtglobal.cpp
qxtglobalshortcut.cpp
@@ -12,7 +20,6 @@ set(QXT-MOC-HEADERS
find_package(X11)
include_directories(${X11_INCLUDE_DIR})
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)

View File

@@ -38,36 +38,36 @@
#include "qxtglobalshortcut_p.h"
bool QxtGlobalShortcutPrivate::error = false;
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
int QxtGlobalShortcutPrivate::ref = 0;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
{
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
if (!ref++)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
#else
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
}
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
{
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
if (!--ref)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
#else
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
}
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)

View File

@@ -59,7 +59,7 @@ public:
bool unsetShortcut();
static bool error;
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
static int ref;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
static QAbstractEventDispatcher::EventFilter prevEventFilter;
@@ -67,7 +67,7 @@ public:
#else
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
#endif // Q_WS_MAC
#endif // Q_OS_MAC
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);

View File

@@ -1,7 +1,7 @@
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
@@ -16,7 +16,7 @@
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@@ -1,7 +1,7 @@
/*
* FILE: sha2.h
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
@@ -16,7 +16,7 @@
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@@ -47,6 +47,8 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/s3m
${CMAKE_CURRENT_SOURCE_DIR}/it
${CMAKE_CURRENT_SOURCE_DIR}/xm
${CMAKE_CURRENT_SOURCE_DIR}/dsf
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
${CMAKE_SOURCE_DIR}/3rdparty
)
@@ -161,6 +163,11 @@ set(tag_HDRS
s3m/s3mproperties.h
xm/xmfile.h
xm/xmproperties.h
dsf/dsffile.h
dsf/dsfproperties.h
dsdiff/dsdifffile.h
dsdiff/dsdiffproperties.h
dsdiff/dsdiffdiintag.h
)
set(mpeg_SRCS
@@ -316,6 +323,17 @@ set(xm_SRCS
xm/xmproperties.cpp
)
set(dsf_SRCS
dsf/dsffile.cpp
dsf/dsfproperties.cpp
)
set(dsdiff_SRCS
dsdiff/dsdifffile.cpp
dsdiff/dsdiffproperties.cpp
dsdiff/dsdiffdiintag.cpp
)
set(toolkit_SRCS
toolkit/tstring.cpp
toolkit/tstringlist.cpp
@@ -347,7 +365,7 @@ set(tag_LIB_SRCS
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} ${dsf_SRCS} ${dsdiff_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp

View File

@@ -38,6 +38,8 @@
#include "vorbisproperties.h"
#include "wavproperties.h"
#include "wavpackproperties.h"
#include "dsfproperties.h"
#include "dsdiffproperties.h"
#include "audioproperties.h"
@@ -73,6 +75,10 @@ using namespace TagLib;
return dynamic_cast<const Vorbis::Properties*>(this)->function_name(); \
else if(dynamic_cast<const WavPack::Properties*>(this)) \
return dynamic_cast<const WavPack::Properties*>(this)->function_name(); \
else if(dynamic_cast<const DSF::Properties*>(this)) \
return dynamic_cast<const DSF::Properties*>(this)->function_name(); \
else if(dynamic_cast<const DSDIFF::Properties*>(this)) \
return dynamic_cast<const DSDIFF::Properties*>(this)->function_name(); \
else \
return (default_value);

162
3rdparty/taglib/dsdiff/dsdiffdiintag.cpp vendored Normal file
View File

@@ -0,0 +1,162 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "dsdiffdiintag.h"
#include "tstringlist.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace DSDIFF::DIIN;
class DSDIFF::DIIN::Tag::TagPrivate
{
public:
TagPrivate()
{
}
String title;
String artist;
};
DSDIFF::DIIN::Tag::Tag() : TagLib::Tag()
{
d = new TagPrivate;
}
DSDIFF::DIIN::Tag::~Tag()
{
delete d;
}
String DSDIFF::DIIN::Tag::title() const
{
return d->title;
}
String DSDIFF::DIIN::Tag::artist() const
{
return d->artist;
}
String DSDIFF::DIIN::Tag::album() const
{
return String();
}
String DSDIFF::DIIN::Tag::comment() const
{
return String();
}
String DSDIFF::DIIN::Tag::genre() const
{
return String();
}
unsigned int DSDIFF::DIIN::Tag::year() const
{
return 0;
}
unsigned int DSDIFF::DIIN::Tag::track() const
{
return 0;
}
void DSDIFF::DIIN::Tag::setTitle(const String &title)
{
if(title.isNull() || title.isEmpty())
d->title = String();
else
d->title = title;
}
void DSDIFF::DIIN::Tag::setArtist(const String &artist)
{
if(artist.isNull() || artist.isEmpty())
d->artist = String();
else
d->artist = artist;
}
void DSDIFF::DIIN::Tag::setAlbum(const String &)
{
}
void DSDIFF::DIIN::Tag::setComment(const String &)
{
}
void DSDIFF::DIIN::Tag::setGenre(const String &)
{
}
void DSDIFF::DIIN::Tag::setYear(unsigned int)
{
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int)
{
}
PropertyMap DSDIFF::DIIN::Tag::properties() const
{
PropertyMap properties;
properties["TITLE"] = d->title;
properties["ARTIST"] = d->artist;
return properties;
}
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap properties(origProps);
properties.removeEmpty();
StringList oneValueSet;
if(properties.contains("TITLE")) {
d->title = properties["TITLE"].front();
oneValueSet.append("TITLE");
} else
d->title = String();
if(properties.contains("ARTIST")) {
d->artist = properties["ARTIST"].front();
oneValueSet.append("ARTIST");
} else
d->artist = String();
// for each tag that has been set above, remove the first entry in the corresponding
// value list. The others will be returned as unsupported by this format.
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
properties.erase(*it);
else
properties[*it].erase(properties[*it].begin());
}
return properties;
}

150
3rdparty/taglib/dsdiff/dsdiffdiintag.h vendored Normal file
View File

@@ -0,0 +1,150 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFDIINTAG_H
#define TAGLIB_DSDIFFDIINTAG_H
#include "tag.h"
namespace TagLib {
namespace DSDIFF {
namespace DIIN {
/*!
* Tags from the Edited Master Chunk Info
*
* Only Title and Artist tags are supported
*/
class TAGLIB_EXPORT Tag : public TagLib::Tag
{
public:
Tag();
virtual ~Tag();
/*!
* Returns the track name; if no track name is present in the tag
* String() will be returned.
*/
String title() const;
/*!
* Returns the artist name; if no artist name is present in the tag
* String() will be returned.
*/
String artist() const;
/*!
* Not supported. Therefore always returns String().
*/
String album() const;
/*!
* Not supported. Therefore always returns String().
*/
String comment() const;
/*!
* Not supported. Therefore always returns String().
*/
String genre() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int year() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int track() const;
/*!
* Sets the title to \a title. If \a title is String() then this
* value will be cleared.
*/
void setTitle(const String &title);
/*!
* Sets the artist to \a artist. If \a artist is String() then this
* value will be cleared.
*/
void setArtist(const String &artist);
/*!
* Not supported and therefore ignored.
*/
void setAlbum(const String &album);
/*!
* Not supported and therefore ignored.
*/
void setComment(const String &comment);
/*!
* Not supported and therefore ignored.
*/
void setGenre(const String &genre);
/*!
* Not supported and therefore ignored.
*/
void setYear(unsigned int year);
/*!
* Not supported and therefore ignored.
*/
void setTrack(unsigned int track);
/*!
* Implements the unified property interface -- export function.
* Since the DIIN tag is very limited, the exported map is as well.
*/
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* Because of the limitations of the DIIN file tag, any tags besides
* TITLE and ARTIST, will be
* returned. Additionally, if the map contains tags with multiple values,
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
}
#endif

812
3rdparty/taglib/dsdiff/dsdifffile.cpp vendored Normal file
View File

@@ -0,0 +1,812 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "tagunion.h"
#include "dsdifffile.h"
using namespace TagLib;
struct Chunk64
{
ByteVector name;
unsigned long long offset;
unsigned long long size;
char padding;
};
namespace
{
enum {
ID3v2Index = 0,
DIINIndex = 1
};
enum {
PROPChunk = 0,
DIINChunk = 1
};
}
class DSDIFF::File::FilePrivate
{
public:
FilePrivate() :
endianness(BigEndian),
size(0),
isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1),
properties(0),
id3v2TagChunkID("ID3 "),
hasID3v2(false),
hasDiin(false)
{
childChunkIndex[ID3v2Index] = -1;
childChunkIndex[DIINIndex] = -1;
}
~FilePrivate()
{
delete properties;
}
Endianness endianness;
ByteVector type;
unsigned long long size;
ByteVector format;
std::vector<Chunk64> chunks;
std::vector<Chunk64> childChunks[2];
int childChunkIndex[2];
bool isID3InPropChunk; // Two possibilities can be found: ID3V2 chunk inside PROP chunk or at root level
int duplicateID3V2chunkIndex; // 2 ID3 chunks are present. This is then the index of the one in
// PROP chunk that will be removed upon next save to remove duplicates.
Properties *properties;
TagUnion tag;
ByteVector id3v2TagChunkID;
bool hasID3v2;
bool hasDiin;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSDIFF::File::isSupported(IOStream *stream)
{
// A DSDIFF file has to start with "FRM8????????DSD ".
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::~File()
{
delete d;
}
TagLib::Tag *DSDIFF::File::tag() const
{
return &d->tag;
}
ID3v2::Tag *DSDIFF::File::ID3v2Tag() const
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, false);
}
bool DSDIFF::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
DSDIFF::DIIN::Tag *DSDIFF::File::DIINTag() const
{
return d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
}
bool DSDIFF::File::hasDIINTag() const
{
return d->hasDiin;
}
PropertyMap DSDIFF::File::properties() const
{
if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
return PropertyMap();
}
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
if(d->hasID3v2)
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
if(d->hasDiin)
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
}
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties)
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
}
DSDIFF::Properties *DSDIFF::File::audioProperties() const
{
return d->properties;
}
bool DSDIFF::File::save()
{
if(readOnly()) {
debug("DSDIFF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSDIFF::File::save() -- Trying to save invalid file.");
return false;
}
// First: save ID3V2 chunk
ID3v2::Tag *id3v2Tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false);
if(d->isID3InPropChunk) {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setChildChunkData(d->id3v2TagChunkID, id3v2Tag->render(), PROPChunk);
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setChildChunkData(d->id3v2TagChunkID, ByteVector(), PROPChunk);
d->hasID3v2 = false;
}
}
else {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setRootChunkData(d->id3v2TagChunkID, id3v2Tag->render());
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setRootChunkData(d->id3v2TagChunkID, ByteVector());
d->hasID3v2 = false;
}
}
// Second: save the DIIN chunk
if(d->hasDiin) {
DSDIFF::DIIN::Tag *diinTag = d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
if(!diinTag->title().isNull() && !diinTag->title().isEmpty()) {
ByteVector diinTitle;
diinTitle.append(ByteVector::fromUInt(diinTag->title().size(), d->endianness == BigEndian));
diinTitle.append(ByteVector::fromCString(diinTag->title().toCString()));
setChildChunkData("DITI", diinTitle, DIINChunk);
}
else
setChildChunkData("DITI", ByteVector(), DIINChunk);
if(!diinTag->artist().isNull() && !diinTag->artist().isEmpty()) {
ByteVector diinArtist;
diinArtist.append(ByteVector::fromUInt(diinTag->artist().size(), d->endianness == BigEndian));
diinArtist.append(ByteVector::fromCString(diinTag->artist().toCString()));
setChildChunkData("DIAR", diinArtist, DIINChunk);
}
else
setChildChunkData("DIAR", ByteVector(), DIINChunk);
}
// Third: remove the duplicate ID3V2 chunk (inside PROP chunk) if any
if(d->duplicateID3V2chunkIndex>=0) {
setChildChunkData(d->duplicateID3V2chunkIndex, ByteVector(), PROPChunk);
d->duplicateID3V2chunkIndex = -1;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
{
if(data.isNull() || data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = d->chunks[i].size + d->chunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
removeBlock(d->chunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
for(unsigned long r = i + 1; r < d->chunks.size(); r++)
d->chunks[r].offset = d->chunks[r - 1].offset + 12
+ d->chunks[r - 1].size + d->chunks[r - 1].padding;
d->chunks.erase(d->chunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Now update the specific chunk
writeChunk(d->chunks[i].name,
data,
d->chunks[i].offset - 12,
d->chunks[i].size + d->chunks[i].padding + 12);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Finally update the internal offsets
updateRootChunksStructure(i + 1);
}
}
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data)
{
if(d->chunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
setRootChunkData(i, data);
return;
}
}
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = d->chunks.size() - 1;
unsigned long offset = d->chunks[i].offset + d->chunks[i].size + d->chunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Now add the chunk to the file
writeChunk(name,
data,
offset,
std::max<unsigned long long>(0, length() - offset),
(offset & 1) ? 1 : 0);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
d->chunks.push_back(chunk);
}
void DSDIFF::File::setChildChunkData(unsigned int i,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(data.isNull() || data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Update child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Remove the chunk
removeBlock(childChunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
// For child chunks
if((i + 1) < childChunks.size()) {
childChunks[i + 1].offset = childChunks[i].offset;
i++;
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
}
// And for root chunks
for(i = d->childChunkIndex[childChunkNum] + 1; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
childChunks.erase(childChunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding);
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// And the PROP chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += ((data.size() + 1) & ~1)
- (childChunks[i].size + childChunks[i].padding);
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now update the specific chunk
writeChunk(childChunks[i].name,
data,
childChunks[i].offset - 12,
childChunks[i].size + childChunks[i].padding + 12);
childChunks[i].size = data.size();
childChunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
// For child Chunks
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
// And for root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
}
}
void DSDIFF::File::setChildChunkData(const ByteVector &name,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(childChunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < childChunks.size(); i++) {
if(childChunks[i].name == name) {
setChildChunkData(i, data, childChunkNum);
return;
}
}
// Do not attempt to remove a non existing chunk
if(data.isNull() || data.isEmpty())
return;
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = childChunks.size() - 1;
unsigned long offset = childChunks[i].offset + childChunks[i].size + childChunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// And the child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1)
+ ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now add the chunk to the file
unsigned long long nextRootChunkIdx = length();
if((d->childChunkIndex[childChunkNum] + 1) < static_cast<int>(d->chunks.size()))
nextRootChunkIdx = d->chunks[d->childChunkIndex[childChunkNum] + 1].offset - 12;
writeChunk(name, data, offset,
std::max<unsigned long long>(0, nextRootChunkIdx - offset),
(offset & 1) ? 1 : 0);
// For root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
childChunks.push_back(chunk);
}
static bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4)
return false;
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127)
return false;
}
return true;
}
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk)
{
for(unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
// Update childchunks structure as well
if(d->childChunkIndex[PROPChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[PROPChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[PROPChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
if(d->childChunkIndex[DIINChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[DIINChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[DIINChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
}
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
bool bigEndian = (d->endianness == BigEndian);
d->type = readBlock(4);
d->size = readBlock(8).toLongLong(bigEndian);
d->format = readBlock(4);
// + 12: chunk header at least, fix for additional junk bytes
while(tell() + 12 <= length()) {
ByteVector chunkName = readBlock(4);
unsigned long long chunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(chunkName)) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<unsigned long long>(tell()) + chunkSize > static_cast<unsigned long long>(length())) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName
+ "' has invalid size (larger than the file size)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = chunkName;
chunk.size = chunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->chunks.push_back(chunk);
}
unsigned long long lengthDSDSamplesTimeChannels = 0; // For DSD uncompressed
unsigned long long audioDataSizeinBytes = 0; // For computing bitrate
unsigned long dstNumFrames = 0; // For DST compressed frames
unsigned short dstFrameRate = 0; // For DST compressed frames
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == "DSD ") {
lengthDSDSamplesTimeChannels = d->chunks[i].size * 8;
audioDataSizeinBytes = d->chunks[i].size;
}
else if(d->chunks[i].name == "DST ") {
// Now decode the chunks inside the DST chunk to read the DST Frame Information one
long long dstChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
audioDataSizeinBytes = d->chunks[i].size;
while(tell() + 12 <= dstChunkEnd) {
ByteVector dstChunkName = readBlock(4);
long long dstChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(dstChunkName)) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + dstChunkSize > dstChunkEnd) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName
+ "' has invalid size (larger than the DST chunk)");
setValid(false);
break;
}
if(dstChunkName == "FRTE") {
// Found the DST frame information chunk
dstNumFrames = readBlock(4).toUInt(bigEndian);
dstFrameRate = readBlock(2).toUShort(bigEndian);
break; // Found the wanted one, no need to look at the others
}
seek(dstChunkSize, Current);
// Check padding
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
}
}
}
else if(d->chunks[i].name == "PROP") {
d->childChunkIndex[PROPChunk] = i;
// Now decodes the chunks inside the PROP chunk
long long propChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset + 4); // +4 to remove the 'SND ' marker at beginning of 'PROP' chunk
while(tell() + 12 <= propChunkEnd) {
ByteVector propChunkName = readBlock(4);
long long propChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(propChunkName)) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + propChunkSize > propChunkEnd) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName
+ "' has invalid size (larger than the PROP chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = propChunkName;
chunk.size = propChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[PROPChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "DIIN") {
d->childChunkIndex[DIINChunk] = i;
d->hasDiin = true;
// Now decode the chunks inside the DIIN chunk
long long diinChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
while(tell() + 12 <= diinChunkEnd) {
ByteVector diinChunkName = readBlock(4);
long long diinChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(diinChunkName)) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + diinChunkSize > diinChunkEnd) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName
+ "' has invalid size (larger than the DIIN chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = diinChunkName;
chunk.size = diinChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[DIINChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "ID3 " || d->chunks[i].name == "id3 ") {
d->id3v2TagChunkID = d->chunks[i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->chunks[i].offset));
d->isID3InPropChunk = false;
d->hasID3v2 = true;
}
}
if(!isValid())
return;
if(d->childChunkIndex[PROPChunk] < 0) {
debug("DSDIFF::File::read() -- no PROP chunk found");
setValid(false);
return;
}
// Read properties
unsigned int sampleRate=0;
unsigned short channels=0;
for(unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) {
if(d->childChunks[PROPChunk][i].name == "ID3 " || d->childChunks[PROPChunk][i].name == "id3 ") {
if(d->hasID3v2) {
d->duplicateID3V2chunkIndex = i;
continue; // ID3V2 tag has already been found at root level
}
d->id3v2TagChunkID = d->childChunks[PROPChunk][i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->childChunks[PROPChunk][i].offset));
d->isID3InPropChunk = true;
d->hasID3v2 = true;
}
else if(d->childChunks[PROPChunk][i].name == "FS ") {
// Sample rate
seek(d->childChunks[PROPChunk][i].offset);
sampleRate = readBlock(4).toUInt(0, 4, bigEndian);
}
else if(d->childChunks[PROPChunk][i].name == "CHNL") {
// Channels
seek(d->childChunks[PROPChunk][i].offset);
channels = readBlock(2).toShort(0, bigEndian);
}
}
// Read title & artist from DIIN chunk
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, true);
if(d->hasDiin) {
for(unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) {
if(d->childChunks[DIINChunk][i].name == "DITI") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int titleStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(titleStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector titleStr = readBlock(titleStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setTitle(titleStr);
}
}
else if(d->childChunks[DIINChunk][i].name == "DIAR") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int artistStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(artistStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector artistStr = readBlock(artistStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setArtist(artistStr);
}
}
}
}
if(readProperties) {
if(lengthDSDSamplesTimeChannels == 0) {
// DST compressed signal : need to compute length of DSD uncompressed frames
if(dstFrameRate > 0)
lengthDSDSamplesTimeChannels = (unsigned long long)dstNumFrames
* (unsigned long long)sampleRate / (unsigned long long)dstFrameRate;
else
lengthDSDSamplesTimeChannels = 0;
}
else {
// In DSD uncompressed files, the read number of samples is the total for each channel
if(channels > 0)
lengthDSDSamplesTimeChannels /= channels;
}
int bitrate = 0;
if(lengthDSDSamplesTimeChannels > 0)
bitrate = (audioDataSizeinBytes*8*sampleRate) / lengthDSDSamplesTimeChannels / 1000;
d->properties = new Properties(sampleRate,
channels,
lengthDSDSamplesTimeChannels,
bitrate,
propertiesStyle);
}
if(!ID3v2Tag()) {
d->tag.access<ID3v2::Tag>(ID3v2Index, true);
d->isID3InPropChunk = false; // By default, ID3 chunk is at root level
d->hasID3v2 = false;
}
}
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding)
{
ByteVector combined;
if(leadingPadding)
combined.append(ByteVector(leadingPadding, '\x00'));
combined.append(name);
combined.append(ByteVector::fromLongLong(data.size(), d->endianness == BigEndian));
combined.append(data);
if((data.size() & 0x01) != 0)
combined.append('\x00');
insert(combined, offset, replace);
}

260
3rdparty/taglib/dsdiff/dsdifffile.h vendored Normal file
View File

@@ -0,0 +1,260 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFFILE_H
#define TAGLIB_DSDIFFFILE_H
#include "rifffile.h"
#include "id3v2tag.h"
#include "dsdiffproperties.h"
#include "dsdiffdiintag.h"
namespace TagLib {
//! An implementation of DSDIFF metadata
/*!
* This is implementation of DSDIFF metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* chunk as well as properties from the file.
* Description of the DSDIFF format is available
* at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
* DSDIFF standard does not explictly specify the ID3V2 chunk
* It can be found at the root level, but also sometimes inside the PROP chunk
* In addition, title and artist info are stored as part of the standard
*/
namespace DSDIFF {
//! An implementation of TagLib::File with DSDIFF specific methods
/*!
* This implements and provides an interface for DSDIFF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSDIFF files.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Constructs an DSDIFF file from \a file. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Constructs an DSDIFF file from \a stream. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
* tags. The ID3v2 tag is given priority in reading the information -- if
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
* the information from the ID3v2 tag will be returned.
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use the tag-type specific calls.
*
* \note As this tag is not implemented as an ID3v2 tag or a DIIN tag,
* but a union of the two this pointer may not be cast to the specific
* tag types.
*
* \see ID3v2Tag()
* \see DIINTag()
*/
virtual Tag *tag() const;
/*!
* Returns the ID3V2 Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the
* file on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
virtual ID3v2::Tag *ID3v2Tag() const;
/*!
* Returns the DSDIFF DIIN Tag for this file
*
*/
DSDIFF::DIIN::Tag *DIINTag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the AIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
* will duplicate its content into the other tag. This returns true
* if saving was successful.
*
* If neither exists or if both tags are empty, this will strip the tags
* from the file.
*
* This is the same as calling save(AllTags);
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use paramaterized save call below.
*
* \see save(int tags)
*/
virtual bool save();
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
*
* This strips all tags not included in the mask, but does not modify them
* in memory, so later calls to save() which make use of these tags will
* remain valid. This also strips empty tags.
*/
bool save(int tags);
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* Title & Artist tag.
*
* \see DIINTag()
*/
bool hasDIINTag() const;
/*!
* Returns whether or not the given \a stream can be opened as a DSDIFF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
protected:
enum Endianness { BigEndian, LittleEndian };
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
private:
File(const File &);
File &operator=(const File &);
/*!
* Sets the data for the the specified chunk at root level to \a data.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(unsigned int i, const ByteVector &data);
/*!
* Sets the data for the root-level chunk \a name to \a data.
* If a root-level chunk with the given name already exists
* it will be overwritten, otherwise it will be
* created after the existing chunks.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(const ByteVector &name, const ByteVector &data);
/*!
* Sets the data for the the specified child chunk to \a data.
*
* If data is null, then remove the chunk
*
* \warning This will update the file immediately.
*/
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
/*!
* Sets the data for the child chunk \a name to \a data. If a chunk with
* the given name already exists it will be overwritten, otherwise it will
* be created after the existing chunks inside child chunk.
*
* If data is null, then remove the chunks with \a name name
*
* \warning This will update the file immediately.
*/
void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum);
void updateRootChunksStructure(unsigned int startingChunk);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,120 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsdiffproperties.h"
using namespace TagLib;
class DSDIFF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
sampleWidth(0),
sampleCount(0)
{
}
int length;
int bitrate;
int sampleRate;
int channels;
int sampleWidth;
unsigned long long sampleCount;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::Properties::Properties(const unsigned int sampleRate,
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : AudioProperties(style)
{
d = new PropertiesPrivate;
d->channels = channels;
d->sampleCount = samplesCount;
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5)
: 0;
}
DSDIFF::Properties::~Properties()
{
delete d;
}
int DSDIFF::Properties::length() const
{
return lengthInSeconds();
}
int DSDIFF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSDIFF::Properties::lengthInMilliseconds() const
{
return d->length;
}
int DSDIFF::Properties::bitrate() const
{
return d->bitrate;
}
int DSDIFF::Properties::sampleRate() const
{
return d->sampleRate;
}
int DSDIFF::Properties::channels() const
{
return d->channels;
}
int DSDIFF::Properties::bitsPerSample() const
{
return d->sampleWidth;
}
long long DSDIFF::Properties::sampleCount() const
{
return d->sampleCount;
}

View File

@@ -0,0 +1,83 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFPROPERTIES_H
#define TAGLIB_DSDIFFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSDIFF {
class File;
//! An implementation of audio property reading for DSDIFF
/*!
* This reads the data from an DSDIFF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
* Create an instance of DSDIFF::Properties with the data read from the
* ByteVector \a data.
*/
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*!
* Destroys this DSDIFF::Properties instance.
*/
virtual ~Properties();
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int bitsPerSample() const;
long long sampleCount() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

241
3rdparty/taglib/dsf/dsffile.cpp vendored Normal file
View File

@@ -0,0 +1,241 @@
/***************************************************************************
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "dsffile.h"
using namespace TagLib;
// The DSF specification is located at http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
class DSF::File::FilePrivate
{
public:
FilePrivate() :
properties(0),
tag(0)
{
}
~FilePrivate()
{
delete properties;
delete tag;
}
long long fileSize;
long long metadataOffset;
Properties *properties;
ID3v2::Tag *tag;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSF::File::isSupported(IOStream *stream)
{
// A DSF file has to start with "DSD "
const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("DSD ");
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) :
TagLib::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
DSF::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
DSF::File::~File()
{
delete d;
}
ID3v2::Tag *DSF::File::tag() const
{
return d->tag;
}
PropertyMap DSF::File::properties() const
{
return d->tag->properties();
}
PropertyMap DSF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
DSF::Properties *DSF::File::audioProperties() const
{
return d->properties;
}
bool DSF::File::save()
{
if(readOnly()) {
debug("DSF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSF::File::save() -- Trying to save invalid file.");
return false;
}
// Three things must be updated: the file size, the tag data, and the metadata offset
if(d->tag->isEmpty()) {
long long newFileSize = d->metadataOffset ? d->metadataOffset : d->fileSize;
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset to 0 since there is no longer a tag
if(d->metadataOffset) {
insert(ByteVector::fromLongLong(0ULL, false), 20, 8);
d->metadataOffset = 0;
}
// Delete the old tag
truncate(newFileSize);
}
else {
ByteVector tagData = d->tag->render();
long long newMetadataOffset = d->metadataOffset ? d->metadataOffset : d->fileSize;
long long newFileSize = newMetadataOffset + tagData.size();
long long oldTagSize = d->fileSize - newMetadataOffset;
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset
if(d->metadataOffset != newMetadataOffset) {
insert(ByteVector::fromLongLong(newMetadataOffset, false), 20, 8);
d->metadataOffset = newMetadataOffset;
}
// Delete the old tag and write the new one
insert(tagData, newMetadataOffset, static_cast<size_t>(oldTagSize));
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
// A DSF file consists of four chunks: DSD chunk, format chunk, data chunk, and metadata chunk
// The file format is not chunked in the sense of a RIFF File, though
// DSD chunk
ByteVector chunkName = readBlock(4);
if(chunkName != "DSD ") {
debug("DSF::File::read() -- Not a DSF file.");
setValid(false);
return;
}
long long chunkSize = readBlock(8).toLongLong(false);
// Integrity check
if(28 != chunkSize) {
debug("DSF::File::read() -- File is corrupted, wrong chunk size");
setValid(false);
return;
}
d->fileSize = readBlock(8).toLongLong(false);
// File is malformed or corrupted
if(d->fileSize != length()) {
debug("DSF::File::read() -- File is corrupted wrong length");
setValid(false);
return;
}
d->metadataOffset = readBlock(8).toLongLong(false);
// File is malformed or corrupted
if(d->metadataOffset > d->fileSize) {
debug("DSF::File::read() -- Invalid metadata offset.");
setValid(false);
return;
}
// Format chunk
chunkName = readBlock(4);
if(chunkName != "fmt ") {
debug("DSF::File::read() -- Missing 'fmt ' chunk.");
setValid(false);
return;
}
chunkSize = readBlock(8).toLongLong(false);
d->properties = new Properties(readBlock(chunkSize), propertiesStyle);
// Skip the data chunk
// A metadata offset of 0 indicates the absence of an ID3v2 tag
if(0 == d->metadataOffset)
d->tag = new ID3v2::Tag();
else
d->tag = new ID3v2::Tag(this, d->metadataOffset);
}

128
3rdparty/taglib/dsf/dsffile.h vendored Normal file
View File

@@ -0,0 +1,128 @@
/***************************************************************************
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFFILE_H
#define TAGLIB_DSFFILE_H
#include "tfile.h"
#include "id3v2tag.h"
#include "dsfproperties.h"
namespace TagLib {
//! An implementation of DSF metadata
/*!
* This is implementation of DSF metadata.
*
* This supports an ID3v2 tag as well as properties from the file.
*/
namespace DSF {
//! An implementation of TagLib::File with DSF specific methods
/*!
* This implements and provides an interface for DSF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSF files.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the Tag for this file.
*/
ID3v2::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the DSF::AudioProperties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Saves the file.
*/
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as a DSF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

161
3rdparty/taglib/dsf/dsfproperties.cpp vendored Normal file
View File

@@ -0,0 +1,161 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsfproperties.h"
using namespace TagLib;
class DSF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
formatVersion(0),
formatID(0),
channelType(0),
channelNum(0),
samplingFrequency(0),
bitsPerSample(0),
sampleCount(0),
blockSizePerChannel(0),
bitrate(0),
length(0)
{
}
// Nomenclature is from DSF file format specification
unsigned int formatVersion;
unsigned int formatID;
unsigned int channelType;
unsigned int channelNum;
unsigned int samplingFrequency;
unsigned int bitsPerSample;
long long sampleCount;
unsigned int blockSizePerChannel;
// Computed
unsigned int bitrate;
unsigned int length;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::Properties::Properties(const ByteVector &data, ReadStyle style) : TagLib::AudioProperties(style)
{
d = new PropertiesPrivate;
read(data);
}
DSF::Properties::~Properties()
{
delete d;
}
int DSF::Properties::length() const
{
return lengthInSeconds();
}
int DSF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSF::Properties::lengthInMilliseconds() const
{
return d->length;
}
int DSF::Properties::bitrate() const
{
return d->bitrate;
}
int DSF::Properties::sampleRate() const
{
return d->samplingFrequency;
}
int DSF::Properties::channels() const
{
return d->channelNum;
}
// DSF specific
int DSF::Properties::formatVersion() const
{
return d->formatVersion;
}
int DSF::Properties::formatID() const
{
return d->formatID;
}
int DSF::Properties::channelType() const
{
return d->channelType;
}
int DSF::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
long long DSF::Properties::sampleCount() const
{
return d->sampleCount;
}
int DSF::Properties::blockSizePerChannel() const
{
return d->blockSizePerChannel;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::Properties::read(const ByteVector &data)
{
d->formatVersion = data.toUInt(0U,false);
d->formatID = data.toUInt(4U,false);
d->channelType = data.toUInt(8U,false);
d->channelNum = data.toUInt(12U,false);
d->samplingFrequency = data.toUInt(16U,false);
d->bitsPerSample = data.toUInt(20U,false);
d->sampleCount = data.toLongLong(24U,false);
d->blockSizePerChannel = data.toUInt(32U,false);
d->bitrate
= static_cast<unsigned int>((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0 + 0.5);
d->length
= d->samplingFrequency > 0 ? static_cast<unsigned int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5) : 0;
}

92
3rdparty/taglib/dsf/dsfproperties.h vendored Normal file
View File

@@ -0,0 +1,92 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFPROPERTIES_H
#define TAGLIB_DSFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSF {
class File;
//! An implementation of audio property reading for DSF
/*!
* This reads the data from a DSF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of DSF::AudioProperties with the data read from the
* ByteVector \a data.
*/
Properties(const ByteVector &data, ReadStyle style);
/*!
* Destroys this DSF::AudioProperties instance.
*/
virtual ~Properties();
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int formatVersion() const;
int formatID() const;
/*!
* Channel type values: 1 = mono, 2 = stereo, 3 = 3 channels,
* 4 = quad, 5 = 4 channels, 6 = 5 channels, 7 = 5.1 channels
*/
int channelType() const;
int bitsPerSample() const;
long long sampleCount() const;
int blockSizePerChannel() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(const ByteVector &data);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

View File

@@ -52,6 +52,8 @@
#include "s3mfile.h"
#include "itfile.h"
#include "xmfile.h"
#include "dsffile.h"
#include "dsdifffile.h"
using namespace TagLib;
@@ -135,6 +137,10 @@ namespace
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
return 0;
}
@@ -174,6 +180,10 @@ namespace
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSDIFF::File::isSupported(stream))
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSF::File::isSupported(stream))
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
// isSupported() only does a quick check, so double check the file here.
@@ -255,6 +265,10 @@ namespace
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle);
return 0;
}
@@ -387,6 +401,9 @@ StringList FileRef::defaultFileExtensions()
l.append("s3m");
l.append("it");
l.append("xm");
l.append("dsf");
l.append("dff");
l.append("dsdiff"); // alias for "dff"
return l;
}

View File

@@ -216,7 +216,23 @@ void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
String TableOfContentsFrame::toString() const
{
return String();
String s = String(d->elementID) +
": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false");
if(!d->childElements.isEmpty()) {
s+= ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
}
if(!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
return s;
}
PropertyMap TableOfContentsFrame::asProperties() const

View File

@@ -339,7 +339,13 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const String &descripti
String UserTextIdentificationFrame::toString() const
{
return "[" + description() + "] " + fieldList().toString();
// first entry is the description itself, drop from values list
StringList l = fieldList();
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
l.erase(it);
break;
}
return "[" + description() + "] " + l.toString();
}
String UserTextIdentificationFrame::description() const

View File

@@ -231,11 +231,21 @@ void Ogg::FLAC::File::scan()
if(!metadataHeader.startsWith("fLaC")) {
// FLAC 1.1.2+
// See https://xiph.org/flac/ogg_mapping.html for the header specification.
if(metadataHeader.size() < 13)
return;
if(metadataHeader[0] != 0x7f)
return;
if(metadataHeader.mid(1, 4) != "FLAC")
return;
if(metadataHeader[5] != 1)
return; // not version 1
if(metadataHeader[5] != 1 && metadataHeader[6] != 0)
return; // not version 1.0
if(metadataHeader.mid(9, 4) != "fLaC")
return;
metadataHeader = metadataHeader.mid(13);
}

View File

@@ -63,6 +63,8 @@
#include "itfile.h"
#include "xmfile.h"
#include "mp4file.h"
#include "dsffile.h"
#include "dsdifffile.h"
using namespace TagLib;
@@ -148,6 +150,10 @@ PropertyMap File::properties() const
return dynamic_cast<const MP4::File* >(this)->properties();
if(dynamic_cast<const ASF::File* >(this))
return dynamic_cast<const ASF::File* >(this)->properties();
if(dynamic_cast<const DSF::File* >(this))
return dynamic_cast<const DSF::File* >(this)->properties();
if(dynamic_cast<const DSDIFF::File* >(this))
return dynamic_cast<const DSDIFF::File* >(this)->properties();
return tag()->properties();
}
@@ -177,6 +183,10 @@ void File::removeUnsupportedProperties(const StringList &properties)
dynamic_cast<MP4::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<ASF::File* >(this))
dynamic_cast<ASF::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<DSF::File* >(this))
dynamic_cast<DSF::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<DSDIFF::File* >(this))
dynamic_cast<DSDIFF::File* >(this)->removeUnsupportedProperties(properties);
else
tag()->removeUnsupportedProperties(properties);
}
@@ -219,6 +229,10 @@ PropertyMap File::setProperties(const PropertyMap &properties)
return dynamic_cast<MP4::File* >(this)->setProperties(properties);
else if(dynamic_cast<ASF::File* >(this))
return dynamic_cast<ASF::File* >(this)->setProperties(properties);
else if(dynamic_cast<DSF::File* >(this))
return dynamic_cast<DSF::File* >(this)->setProperties(properties);
else if(dynamic_cast<DSDIFF::File* >(this))
return dynamic_cast<DSDIFF::File* >(this)->setProperties(properties);
else
return tag()->setProperties(properties);
}

View File

@@ -58,6 +58,11 @@ namespace
#endif
}
FileHandle openFile(const int fileDescriptor, bool readOnly)
{
return InvalidFileHandle;
}
void closeFile(FileHandle file)
{
CloseHandle(file);
@@ -98,6 +103,11 @@ namespace
return fopen(path, readOnly ? "rb" : "rb+");
}
FileHandle openFile(const int fileDescriptor, bool readOnly)
{
return fdopen(fileDescriptor, readOnly ? "rb" : "rb+");
}
void closeFile(FileHandle file)
{
fclose(file);
@@ -149,13 +159,28 @@ FileStream::FileStream(FileName fileName, bool openReadOnly)
d->file = openFile(fileName, true);
if(d->file == InvalidFileHandle)
{
# ifdef _WIN32
debug("Could not open file " + fileName.toString());
# else
debug("Could not open file " + String(static_cast<const char *>(d->name)));
# endif
}
}
FileStream::FileStream(int fileDescriptor, bool openReadOnly)
: d(new FileStreamPrivate(""))
{
// First try with read / write mode, if that fails, fall back to read only.
if(!openReadOnly)
d->file = openFile(fileDescriptor, false);
if(d->file != InvalidFileHandle)
d->readOnly = false;
else
d->file = openFile(fileDescriptor, true);
if(d->file == InvalidFileHandle)
debug("Could not open file using file descriptor");
}
FileStream::~FileStream()
@@ -255,8 +280,7 @@ void FileStream::insert(const ByteVector &data, unsigned long start, unsigned lo
ByteVector buffer = data;
ByteVector aboutToOverwrite(static_cast<unsigned int>(bufferLength));
while(true)
{
while(true) {
// Seek to the current read position and read the data that we're about
// to overwrite. Appropriately increment the readPosition.
@@ -304,8 +328,7 @@ void FileStream::removeBlock(unsigned long start, unsigned long length)
ByteVector buffer(static_cast<unsigned int>(bufferLength));
for(unsigned int bytesRead = -1; bytesRead != 0;)
{
for(unsigned int bytesRead = -1; bytesRead != 0;) {
seek(readPosition);
bytesRead = static_cast<unsigned int>(readFile(d->file, buffer));
readPosition += bytesRead;
@@ -401,7 +424,8 @@ long FileStream::tell() const
const LARGE_INTEGER zero = {};
LARGE_INTEGER position;
if(SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) && position.QuadPart <= LONG_MAX) {
if(SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) &&
position.QuadPart <= LONG_MAX) {
return static_cast<long>(position.QuadPart);
}
else {
@@ -470,9 +494,8 @@ void FileStream::truncate(long length)
#else
const int error = ftruncate(fileno(d->file), length);
if(error != 0) {
if(error != 0)
debug("FileStream::truncate() -- Coundn't truncate the file.");
}
#endif
}

View File

@@ -54,6 +54,11 @@ namespace TagLib {
*/
FileStream(FileName file, bool openReadOnly = false);
/*!
* Construct a File object and opens the \a file using file descriptor.
*/
FileStream(int fileDescriptor, bool openReadOnly = false);
/*!
* Destroys this FileStream instance.
*/

View File

@@ -1,7 +1,5 @@
# Strawberry Music Player
# Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
# This file was part of Clementine.
# Copyright 2010, David Sansome <me@davidsansome.com>
#
# Strawberry is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,7 +16,12 @@
project(strawberry)
cmake_minimum_required(VERSION 2.8.11)
cmake_policy(SET CMP0054 NEW)
if(${CMAKE_VERSION} VERSION_GREATER "3.0")
cmake_policy(SET CMP0054 NEW)
endif()
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
cmake_policy(SET CMP0072 NEW)
endif()
include(CheckCXXCompilerFlag)
include(CheckIncludeFiles)
@@ -29,26 +32,30 @@ include(cmake/Summary.cmake)
include(cmake/OptionalSource.cmake)
include(cmake/ParseArguments.cmake)
include(cmake/Rpm.cmake)
include(cmake/Deb.cmake)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(LINUX 1)
set(LINUX ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(FREEBSD 1)
set(FREEBSD ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(OPENBSD 1)
set(OPENBSD ON)
endif()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
#set(CMAKE_BUILD_TYPE Debug)
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
add_definitions(-DNDEBUG)
add_definitions(-DQT_NO_DEBUG_OUTPUT)
#add_definitions(-DQT_NO_WARNING_OUTPUT)
endif(${CMAKE_BUILD_TYPE} MATCHES "Release")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(DEBUG ON)
endif()
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
set(CMAKE_COMPILER_IS_CLANGXX 1)
@@ -79,43 +86,47 @@ find_package(Protobuf REQUIRED)
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
if(LINUX)
find_package(ALSA REQUIRED)
find_package(DBus REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
else(LINUX)
find_package(ALSA)
find_package(DBus)
pkg_check_modules(DBUS dbus-1)
endif(LINUX)
if(ALSA_FOUND)
set(HAVE_ALSA ON)
endif()
find_package(X11)
if (NOT APPLE)
find_package(X11)
endif()
if(X11_FOUND)
set(HAVE_X11 ON)
endif()
find_package(OpenGL REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
pkg_check_modules(GSTREAMER_APP gstreamer-app-1.0)
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-1.0)
pkg_check_modules(GSTREAMER_PBUTILS gstreamer-pbutils-1.0)
pkg_check_modules(LIBXINE libxine)
pkg_check_modules(LIBVLC libvlc)
pkg_check_modules(PHONON phonon4qt5)
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.7)
find_package(OpenGL REQUIRED)
pkg_check_modules(CHROMAPRINT REQUIRED libchromaprint)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(CHROMAPRINT libchromaprint)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(LIBXML libxml-2.0)
pkg_check_modules(LIBGLU REQUIRED glu)
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0)
pkg_check_modules(USBMUXD libusbmuxd)
pkg_check_modules(PLIST libplist)
pkg_check_modules(LIBDEEZER libdeezer)
pkg_check_modules(LIBDZMEDIA libdzmedia)
if(WIN32)
find_package(ZLIB REQUIRED)
endif(WIN32)
# QT
set(QT_MIN_VERSION 5.6.0)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core OpenGL Sql Network Xml Widgets Concurrent Test)
set(QT_MIN_VERSION 5.5.1)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Concurrent Widgets Network Sql OpenGL Xml)
if(X11_FOUND)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras)
endif()
@@ -123,27 +134,27 @@ if(DBUS_FOUND)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus)
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION)
endif()
if(NOT APPLE)
find_package(Qt5 COMPONENTS WebKitWidgets)
endif(NOT APPLE)
if(APPLE)
if(NOT QT_MAC_USE_COCOA)
message(FATAL_ERROR "Cocoa support is required")
endif(NOT QT_MAC_USE_COCOA)
endif(APPLE)
if(UNIX AND X11_FOUND AND DBUS_FOUND)
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml Qt5::X11Extras Qt5::DBus)
elseif(UNIX AND X11_FOUND)
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml Qt5::X11Extras)
else()
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml)
find_package(Qt5 REQUIRED COMPONENTS MacExtras)
endif()
if(WIN32)
find_package(Qt5 REQUIRED COMPONENTS WinExtras)
endif()
# Don't try to use webkit if their include directories couldn't be found.
if (NOT QT_QTWEBKIT_INCLUDE_DIR)
set (QT_USE_QTWEBKIT 0)
endif (NOT QT_QTWEBKIT_INCLUDE_DIR)
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml)
if(DBUS_FOUND)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::DBus)
endif()
if(X11_FOUND)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::X11Extras)
endif()
if(APPLE)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::MacExtras)
endif()
if(WIN32)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras)
endif()
# TAGLIB
pkg_check_modules(TAGLIB taglib)
@@ -160,6 +171,10 @@ if (TAGLIB_FOUND AND USE_SYSTEM_TAGLIB)
set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}")
set(CMAKE_REQUIRED_INCLUDES)
set(CMAKE_REQUIRED_LIBRARIES)
find_path(HAVE_TAGLIB_DSFFILE_H taglib/dsffile.h)
if(HAVE_TAGLIB_DSFFILE_H)
set(HAVE_TAGLIB_DSFFILE ON)
endif(HAVE_TAGLIB_DSFFILE_H)
else()
message(STATUS "Using builtin taglib library")
set(TAGLIB_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/taglib/;${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/")
@@ -167,6 +182,7 @@ else()
set(TAGLIB_LIBRARIES tag)
add_subdirectory(3rdparty/utf8-cpp)
add_subdirectory(3rdparty/taglib)
set(HAVE_TAGLIB_DSFFILE ON)
endif()
# LASTFM
@@ -177,9 +193,6 @@ if(LASTFM5_INCLUDE_DIRS AND LASTFM51_INCLUDE_DIRS)
set(HAVE_LIBLASTFM1 ON)
endif()
# CHROMAPRINT
CHECK_INCLUDE_FILES(chromaprint.h CHROMAPRINT_H)
# Use system sha2 if it's available
find_path(SHA2_INCLUDE_DIRS sha2.h)
find_library(SHA2_LIBRARIES sha2)
@@ -198,9 +211,9 @@ endif()
option(USE_SYSTEM_QTSINGLEAPPLICATION "Use system QtSingleApplication library" OFF)
if(USE_SYSTEM_QTSINGLEAPPLICATION)
message(STATUS "Using system QtSingleApplication library")
find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES QtSolutions)
find_library(QTSINGLEAPPLICATION_LIBRARIES QtSolutions_SingleApplication-2.6)
find_library(QTSINGLECOREAPPLICATION_LIBRARIES QtSolutions_SingleCoreApplication-2.6)
find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES qt5/QtSolutions)
find_library(QTSINGLEAPPLICATION_LIBRARIES Qt5Solutions_SingleApplication-2.6)
find_library(QTSINGLECOREAPPLICATION_LIBRARIES Qt5Solutions_SingleCoreApplication-2.6)
else(USE_SYSTEM_QTSINGLEAPPLICATION)
message(STATUS "Using builtin QtSingleApplication library")
add_subdirectory(3rdparty/qtsingleapplication)
@@ -212,11 +225,11 @@ endif(USE_SYSTEM_QTSINGLEAPPLICATION)
option(USE_SYSTEM_QXT "Use system Qxt library" OFF)
if (USE_SYSTEM_QXT)
message(STATUS "Using system Qxt library")
find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES QxtCore)
find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES QxtGui)
find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES qt5/QxtCore)
find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES qt5/QxtWidgets)
set(QXT_INCLUDE_DIRS ${QXTCORE_INCLUDE_DIRS} ${QXTGUI_INCLUDE_DIRS})
# We only need its header. We don't need to link to QxtCore.
find_library(QXT_LIBRARIES QxtGui)
find_library(QXT_LIBRARIES QxtWidgets-qt5)
else (USE_SYSTEM_QXT)
message(STATUS "Using builtin Qxt library")
add_definitions(-DQXT_STATIC -DBUILD_QXT_GUI -DBUILD_QXT_CORE)
@@ -231,11 +244,6 @@ endif (USE_SYSTEM_QXT)
set(QOCOA_LIBRARIES Qocoa)
add_subdirectory(3rdparty/qocoa)
# Windows
if (WIN32)
add_subdirectory(3rdparty/qtwin)
endif (WIN32)
if (APPLE)
find_library(SPARKLE Sparkle)
add_subdirectory(3rdparty/SPMediaKeyTap)
@@ -265,49 +273,48 @@ optional_component(GSTREAMER ON "Engine: GStreamer backend"
DEPENDS "gstreamer-app-1.0" GSTREAMER_APP_FOUND
DEPENDS "gstreamer-audio-1.0" GSTREAMER_AUDIO_FOUND
DEPENDS "gstreamer-tag-1.0" GSTREAMER_TAG_FOUND
DEPENDS "gstreamer-pbutils-1.0" GSTREAMER_PBUTILS_FOUND
)
optional_component(XINE OFF "Engine: Xine backend"
optional_component(XINE ON "Engine: Xine backend"
DEPENDS "libxine" LIBXINE_FOUND
)
optional_component(VLC OFF "Engine: VLC backend"
optional_component(VLC ON "Engine: VLC backend"
DEPENDS "libvlc" LIBVLC_FOUND
)
optional_component(PHONON OFF "Engine: Phonon backend"
optional_component(PHONON OFF "Engine: Phonon backend (UNSTABLE)"
DEPENDS "phonon4qt5" PHONON_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
if (WIN32)
optional_component(DEEZER ON "Engine: Deezer backend"
DEPENDS "libdeezer" LIBDEEZER_FOUND
)
else ()
optional_component(DEEZER ON "Engine: Deezer backend"
DEPENDS "Linux" LINUX
DEPENDS "libdeezer" LIBDEEZER_FOUND
DEPENDS "libpulse" LIBPULSE_FOUND
)
endif()
optional_component(LIBGPOD ON "Devices: iPod classic support"
DEPENDS "libgpod" LIBGPOD_FOUND
)
optional_component(GIO ON "Devices: GIO device backend"
DEPENDS "libgio" GIO_FOUND
DEPENDS "Unix or Windows" "NOT APPLE"
)
optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND
DEPENDS "libplist" PLIST_FOUND
DEPENDS "libusbmuxd" USBMUXD_FOUND
DEPENDS "iPod classic support" HAVE_LIBGPOD
)
optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
)
optional_component(LIBLASTFM ON "Last.fm album cover provider"
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS
)
optional_component(CHROMAPRINT ON "Chromaprint support / Tag fetching from Musicbrainz"
DEPENDS "chromaprint" CHROMAPRINT_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
optional_component(DEVICEKIT ON "Devices: DeviceKit backend"
DEPENDS "D-Bus support" DBUS_FOUND
)
@@ -316,8 +323,24 @@ optional_component(UDISKS2 ON "Devices: UDisks2 backend"
DEPENDS "D-Bus support" DBUS_FOUND
)
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
optional_component(GIO ON "Devices: GIO device backend"
DEPENDS "libgio" GIO_FOUND
DEPENDS "Unix or Windows" "NOT APPLE"
)
optional_component(LIBGPOD ON "Devices: iPod classic support"
DEPENDS "libgpod" LIBGPOD_FOUND
)
optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
)
optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND
DEPENDS "libplist" PLIST_FOUND
DEPENDS "libusbmuxd" USBMUXD_FOUND
DEPENDS "iPod classic support" LIBGPOD_FOUND
)
optional_component(SPARKLE ON "Sparkle integration"
@@ -325,6 +348,18 @@ optional_component(SPARKLE ON "Sparkle integration"
DEPENDS "Sparkle" SPARKLE
)
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
optional_component(STREAM_DEEZER ON "Streaming: Deezer support")
optional_component(DZMEDIA ON "DZMedia"
DEPENDS "libdzmedia" LIBDZMEDIA_FOUND
DEPENDS "Deezer support" HAVE_STREAM_DEEZER
)
if (HAVE_STREAM_DEEZER AND NOT HAVE_DZMEDIA AND NOT HAVE_DEEZER)
message(STATUS "Deezer is enabled, but not DZMedia or Deezer engine, only preview streams will be available.")
endif()
#if(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
#add_subdirectory(ext/gstafc)
#endif(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
@@ -339,6 +374,7 @@ add_definitions(-DQT_NO_CAST_TO_ASCII -DQT_STRICT_ITERATORS)
include_directories(${GLIB_INCLUDE_DIRS})
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
include_directories(${TAGLIB_INCLUDE_DIRS})
if(ENABLE_IMOBILEDEVICE AND IMOBILEDEVICE_VERSION VERSION_GREATER 1.1.1)
set(IMOBILEDEVICE_USES_UDIDS ON)
@@ -362,6 +398,8 @@ add_custom_target(uninstall
# Show a summary of what we have enabled
summary_show()
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON)
message(FATAL_ERROR "You need to enable either GStreamer, Xine, VLC or Phonon to compile!")
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON AND NOT HAVE_DEEZER)
message(FATAL_ERROR "You need to have either GStreamer, Xine, VLC, Phonon or Deezer to compile!")
elseif(NOT HAVE_GSTREAMER)
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
endif()

View File

@@ -2,9 +2,75 @@ Strawberry Music Player
=======================
ChangeLog
Version 0.4.1:
* Fixed crash in analyzer
* Fixed trying to use systray even if the desktop had no systray
* Fixed Tidal login loop bug
* Added Deezer support
* New improved fancy tabwidget
* Fixed bug not loading engine settings
* Moved queue manager into tabbar for easier access
* Fixed crash when changing appearance colors
* Improved error handling between player and engine
* Added setting to allow continue to the next song in the playlist based on error
* Improved Xine engine code
* Moved some settings
* Updated builtin taglib
* Added AppStream data file
* Fixed compiling with Qt 5 versions of system QtSingleApplication and Qxt library
Version 0.3.3:
* Fixed Tidal login
Version 0.3.2:
* Fixed search error not shown in Tidal search
* Added URL handler for Tidal, now retrieving URL's when playing instead of when searching
* Fixed bug in pipeline not setting url
* Fixed bug setting wrong temporary metadata
* Removed device module from windows, since it's not implemented for windows
* Added support for both ALSA hw and plughw
* Added option to change url stream scheme for Tidal
* Added encoding of Tidal token in the source code
* Added encoding of Tidal password in the configuration
Version 0.3.1:
* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
* Fixed playing and context widget getting stuck in play mode when there was an error
* Changed icons for artists in collection, tidal and cover manager
* Removed "search" icon from "Search automatically" checkbox (right click) that looked ugly
* Removed some unused widgets from the src/widgets directory
* Fixed initial size of window and side panel
* Fixed saving window size correctly
* Added Tidal support
* Disabled Amazon cover provider because of revoked API key
* Removed broken xine fader
* Made chromeprint optional
* Added missing names to about dialog
* Made xine enabled only for window debug
* Removed dead code
* Added DSF and DSDIFF/DFF support
* Fixed tagreader crash when saving tags to MP3 files
* Added support for reading/writing lyrics to tags
* Fixed saving tags (APE) for WavPack files
Version 0.2.1:
* Fixed crash with newer Qt
* Fixed setting output/device for Xine and VLC backend
* Improved backend settings to better support multiple backends
* Fixed track slider for Xine, VLC and Phonon
* Fixed compilation on MacOs
* Fixed device selection on MacOs
* Added xine on to windows build
Version 0.1.6:
* Fix crash on exit caused by NVIDIA driver
* Fix PulseAudio device selection
* Fixed crash on exit caused by NVIDIA driver
* Fixed PulseAudio device selection
* Improvements to device selection
Version 0.1.5:
@@ -17,7 +83,7 @@ Version 0.1.4:
Version 0.1.3:
* Audio file detection by content
* Added builtin taglib to 3rdparty to support detecting audio by content instead of just file extension
* Removed unneeded bulitin qsqlite from 3rdparty
* Removed unneeded qsqlite from 3rdparty
* Added sqldrivers\qsqlite.dll for windows build
* Replaced incorrect DLL libgstdirectsoundsink.dll (from gst 1.12.4) instead of libgstdirectsound.dll (from gst 1.14.0) for windows build
* Fixed git versioning

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
from opensuse:tumbleweed
run zypper --non-interactive --gpg-auto-import-keys ref
run zypper --non-interactive --gpg-auto-import-keys dup -l -y
run zypper --non-interactive --gpg-auto-import-keys install \
lsb-release \
git tar make cmake gcc gcc-c++ pkg-config \
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
boost-devel protobuf-devel sqlite3-devel taglib-devel \
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-devel \
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5OpenGL-devel libQt5Sql-devel \
libqt5-qtx11extras-devel libQt5Gui-private-headers-devel libqt5-qtbase-common-devel liblastfm-qt5-devel \
libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel
run mkdir -p /usr/src/app
workdir /usr/src/app
copy . /usr/src/app

View File

@@ -1,55 +1,67 @@
Strawberry Music Player
:strawberry: Strawberry Music Player [![Build Status](https://travis-ci.org/jonaski/strawberry.svg?branch=master)](https://travis-ci.org/jonaski/strawberry)
=======================
README
------
Strawberry is a audio player and music collection organizer. It is a fork of Clementine created in 2013 with a diffrent goal.
It's written in C++ and Qt5. The name is inspired by the band Strawbs.
It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
### Features:
* Website: http://www.strawbs.org/
* Github: https://github.com/jonaski/strawberry
* Buildbot: http://buildbot.strawbs.net/
* Latest builds: http://builds.strawbs.org/
### :heavy_check_mark: Features:
* Play and organize music
* Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
* Audio CD playback
* Native desktop notifications
* Playlists in multiple formats
* Advanced output and device options with support for bit perfect playback on Linux
* Edit tags on music files
* Fetch tags from MusicBrainz
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
* Album cover art from Last.fm, Musicbrainz and Discogs
* Song lyrics from AudD and API Seeds
* Support for multiple backends
* Audio analyzer
* Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal and Deezer support
You can obtain and view the sourcecode on github at: https://github.com/jonaski/strawberry
It has so far been tested to work on Linux, OpenBSD, MacOs and Windows.
It has so far been tested on Linux, OpenBSD and cross compiled for Windows. I have not had a chance to test it on Mac OS X since I don't have a mac.
### :heavy_exclamation_mark: Requirements
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
Requirements
------------
* [GLib, GIO and GObject](https://developer.gnome.org/glib/)
* [POSIX thread (pthread) libraries](http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html)
* [CMake and Make tools](https://cmake.org/)
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* [Protobuf library and compiler](https://developers.google.com/protocol-buffers/)
* [Boost development headers](https://www.boost.org/)
* [Qt 5 with components Core, Gui, Widgets, Concurrent, Network, Sql, Xml, OpenGL, X11Extras and DBus](https://www.qt.io/)
* [SQLite3](https://www.sqlite.org)
* [TagLib 1.11.1 or higher](http://taglib.org/)
* [Chromaprint library](https://acoustid.org/chromaprint)
* [ALSA library (linux)](https://www.alsa-project.org/)
* [DBus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
To build Strawberry from source you need the following installed on your system:
Either GStreamer, Xine, VLC, Deezer or Phonon engine is required, but only GStreamer is fully implemented so far.
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
* glib2, glib2-devel, git, cmake, make, gcc and gcc-c++
* protobuf and development packages
* boost development headers
Deezer streams with full songs are encrypted and only urls for preview streams (MP3) are exposed by the API.
Full length songs requires the use of deezers own engine (Deezer SDK) or the dzmedia library (I dont have it).
Deezer SDK can be found here: https://build-repo.deezer.com/native_sdk/deezer-native-sdk-v1.2.10.zip
* The following Qt5 components are required with additional development packages: Qt5Core, Qt5Widgets, Qt5Network, Qt5Sql, Qt5Xml, Qt5OpenGL, Qt5Concurrent, Qt5Test, 5X11Extras, Qt5WebKit, Qt5WebKitWidget and Qt5DBus.
Optional:
* ALSA and libasound2 with development files
* SQLite3 with development files
* TagLib 1.8 or higher with development files
* libchromaprint with development files
* libglu with development files
* The Qt 5 LastFM library is required for fetching album covers from LastFM.
* [libcdio](https://www.gnu.org/software/libcdio/) - To enable Audio CD support
* [libmtp](http://libmtp.sourceforge.net/) - MTP support.
* [libgpod](http://www.gtkpod.org/libgpod/) - iPod Classic support.
Either GStreamer, Xine or VLC engine is required, but only GStreamer is fully implemented so far.
You should also install the gstreamer plugins: gstreamer-plugins-base, gstreamer-plugins-good and gstreamer-plugins-bad
* The Qt5 specific LastFM library and development files are required for fetching album covers from LastFM.
* To enable CD support for playing audio cd's you need libcdio.
* If you want MTP support you need libmtp.
* If you need iPod Classic support you need libgpod.
Compiling from source
---------------------
### :wrench: Compiling from source
### Get the code:
@@ -64,5 +76,8 @@ Compiling from source
sudo make install
(dont change to the source directory, if you created the build directory inside the source directory type: cmake .. instead).
### :computer: Screenshot
![Browse](https://www.strawbs.org/pictures/screenshot-002-large.png)

6
cmake/Deb.cmake Normal file
View File

@@ -0,0 +1,6 @@
add_custom_target(deb
#COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/dist/debian ${CMAKE_BINARY_DIR}/debian
COMMAND cp -r -p ${CMAKE_SOURCE_DIR}/dist/debian ${CMAKE_BINARY_DIR}/
COMMAND dpkg-buildpackage -b -d -uc -us
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

View File

@@ -1,43 +0,0 @@
if(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
# Already in cache, be silent
set(DBUS_FIND_QUIETLY TRUE)
endif(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
set(DBUS_LIBRARY)
set(DBUS_INCLUDE_DIR)
set(DBUS_ARCH_INCLUDE_DIR)
FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h
/usr/include
/usr/include/dbus-1.0
/usr/local/include
/usr/local/include/dbus-1.0
)
FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h
/usr/lib/include
/usr/lib/dbus-1.0/include
/usr/lib64/include
/usr/lib64/dbus-1.0/include
/usr/local/lib/include
/usr/local/lib/dbus-1.0/include
/usr/local/lib64/include
/usr/local/lib64/dbus-1.0/include
)
FIND_LIBRARY(DBUS_LIBRARY NAMES dbus-1 dbus
PATHS
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
)
if(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MESSAGE(STATUS "D-Bus found: includes in ${DBUS_INCLUDE_DIR}, library in ${DBUS_LIBRARY}")
set(DBUS_FOUND TRUE)
else(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MESSAGE(STATUS "D-Bus not found")
endif(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_LIBRARY DBUS_ARCH_INCLUDE_DIR)

View File

@@ -1,12 +1,66 @@
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
set(MOCK_COMMAND mock CACHE STRING "Command to use for running mock")
set(MOCK_CHROOT suse-x86_64 CACHE STRING "Chroot to use when building an rpm with mock")
set(RPM_DISTRO suse CACHE STRING "Suffix of the rpm file")
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
find_program(LSB_RELEASE_EXEC lsb_release)
find_program(RPMBUILD_EXEC rpmbuild)
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/strawberry.spec
)
if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -is | tr '[:upper:]' '[:lower:]' | cut -d' ' -f1"
OUTPUT_VARIABLE DIST_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | cut -d' ' -f2"
OUTPUT_VARIABLE DIST_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
OUTPUT_VARIABLE DIST_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (DIST_NAME)
message(STATUS "Distro Name: ${DIST_NAME}")
if (DIST_RELEASE)
message(STATUS "Distro Release: ${DIST_RELEASE}")
endif()
if (DIST_VERSION)
message(STATUS "Distro Version: ${DIST_VERSION}")
endif()
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
if (${DIST_NAME} STREQUAL "opensuse")
if (DIST_RELEASE)
if (${DIST_RELEASE} STREQUAL "leap")
if (DIST_VERSION)
set(RPM_DISTRO "lp${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
else()
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
endif()
elseif (${DIST_RELEASE} STREQUAL "tumbleweed")
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
else ()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
else()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND ${RPMBUILD_EXEC} -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
COMMAND ${RPMBUILD_EXEC} -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
)
elseif (${DIST_NAME} STREQUAL "fedora")
if (DIST_VERSION)
set(RPM_DISTRO "${DIST_NAME}${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
else ()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
)
else()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
message(STATUS "RPM Suffix: ${RPM_DISTRO}")
endif()
endif()

View File

@@ -50,7 +50,7 @@ function(optional_component name default description)
set(current_dep_name)
set(missing_deps)
foreach(arg ${ARGN})
foreach(arg ${ARGN})
if(${next_arg_is_dep_name})
set(current_dep_name "${arg}")
set(next_arg_is_dep_name FALSE)

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 1)
set(STRAWBERRY_VERSION_PATCH 6)
set(STRAWBERRY_VERSION_MINOR 4)
set(STRAWBERRY_VERSION_PATCH 1)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)
@@ -22,14 +22,19 @@ if(STRAWBERRY_VERSION_PRERELEASE)
set(STRAWBERRY_VERSION_PACKAGE "${STRAWBERRY_VERSION_PACKAGE}${STRAWBERRY_VERSION_PRERELEASE}")
endif(STRAWBERRY_VERSION_PRERELEASE)
find_program(GIT_EXECUTABLE git)
if(NOT GIT_EXECUTABLE-NOTFOUND)
if(INCLUDE_GIT_REVISION AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
find_program(GIT_EXECUTABLE git)
if(NOT GIT_EXECUTABLE OR GIT_EXECUTABLE-NOTFOUND)
message(FATAL_ERROR "Missing GIT executable." )
endif()
# Get the current working branch
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_INFO_RESULT
RESULT_VARIABLE GIT_CMD_RESULT_BRANCH
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
@@ -38,36 +43,47 @@ if(NOT GIT_EXECUTABLE-NOTFOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long --tags --always
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_INFO_RESULT
RESULT_VARIABLE GIT_CMD_RESULT_REVISION
OUTPUT_VARIABLE GIT_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if(NOT ${GIT_CMD_RESULT_REVISION} EQUAL 0)
message(FATAL_ERROR "GIT command failed to get revision string '${GIT_REVISION}'")
endif()
endif()
if(${GIT_INFO_RESULT} EQUAL 0)
set(HAS_GIT_REVISION ON)
if(FORCE_GIT_REVISION)
set(GIT_REVISION ${FORCE_GIT_REVISION})
endif()
if(GIT_REVISION)
string(REGEX REPLACE "^(.+)-([0-9]+)-(g[a-f0-9]+)$" "\\1;\\2;\\3" GIT_PARTS ${GIT_REVISION})
if(NOT GIT_PARTS)
message(FATAL_ERROR "Failed to parse git revision string '${GIT_REVISION}'")
endif(NOT GIT_PARTS)
endif()
list(LENGTH GIT_PARTS GIT_PARTS_LENGTH)
if(GIT_PARTS_LENGTH EQUAL 3)
list(GET GIT_PARTS 0 GIT_TAGNAME)
list(GET GIT_PARTS 1 GIT_COMMITCOUNT)
list(GET GIT_PARTS 2 GIT_SHA1)
set(HAS_GIT_REVISION ON)
endif(GIT_PARTS_LENGTH EQUAL 3)
endif(${GIT_INFO_RESULT} EQUAL 0)
if(NOT GIT_PARTS_LENGTH EQUAL 3)
message(FATAL_ERROR "Failed to parse git revision string '${GIT_REVISION}'")
endif()
list(GET GIT_PARTS 0 GIT_TAGNAME)
list(GET GIT_PARTS 1 GIT_COMMITCOUNT)
list(GET GIT_PARTS 2 GIT_SHA1)
set(HAS_GIT_REVISION ON)
if(INCLUDE_GIT_REVISION AND HAS_GIT_REVISION)
set(STRAWBERRY_VERSION_DISPLAY "${GIT_REVISION}")
set(STRAWBERRY_VERSION_PACKAGE "${GIT_REVISION}")
set(STRAWBERRY_VERSION_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}")
endif(INCLUDE_GIT_REVISION AND HAS_GIT_REVISION)
endif()
message(STATUS "Strawberry Version:")
message(STATUS "Display: ${STRAWBERRY_VERSION_DISPLAY}")

View File

@@ -1,10 +1,13 @@
<RCC>
<qresource prefix="/">
<file>schema/schema.sql</file>
<file>schema/schema-1.sql</file>
<file>schema/schema-2.sql</file>
<file>schema/schema-3.sql</file>
<file>schema/device-schema.sql</file>
<file>style/mainwindow.css</file>
<file>style/statusview.css</file>
<file>style/strawberry.css</file>
<file>misc/playing_tooltip.txt</file>
<file>misc/oauthsuccess.html</file>
<file>pictures/strawberry.png</file>
<file>pictures/strawbs-transparent.png</file>
<file>pictures/noalbumart.png</file>
@@ -25,456 +28,7 @@
<file>pictures/osd_background.png</file>
<file>pictures/osd_shadow_corner.png</file>
<file>pictures/osd_shadow_edge.png</file>
<file>icons/128x128/albums.png</file>
<file>icons/128x128/alsa.png</file>
<file>icons/128x128/application-exit.png</file>
<file>icons/128x128/applications-internet.png</file>
<file>icons/128x128/bluetooth.png</file>
<file>icons/128x128/cdcase.png</file>
<file>icons/128x128/cd.png</file>
<file>icons/128x128/configure.png</file>
<file>icons/128x128/device-ipod-nano.png</file>
<file>icons/128x128/device-ipod.png</file>
<file>icons/128x128/device-phone.png</file>
<file>icons/128x128/device.png</file>
<file>icons/128x128/device-usb-drive.png</file>
<file>icons/128x128/device-usb-flash.png</file>
<file>icons/128x128/dialog-error.png</file>
<file>icons/128x128/dialog-information.png</file>
<file>icons/128x128/dialog-ok-apply.png</file>
<file>icons/128x128/dialog-password.png</file>
<file>icons/128x128/dialog-warning.png</file>
<file>icons/128x128/document-download.png</file>
<file>icons/128x128/document-new.png</file>
<file>icons/128x128/document-open-folder.png</file>
<file>icons/128x128/document-open.png</file>
<file>icons/128x128/document-save.png</file>
<file>icons/128x128/document-search.png</file>
<file>icons/128x128/download.png</file>
<file>icons/128x128/edit-clear-list.png</file>
<file>icons/128x128/edit-clear-locationbar-ltr.png</file>
<file>icons/128x128/edit-copy.png</file>
<file>icons/128x128/edit-delete.png</file>
<file>icons/128x128/edit-find.png</file>
<file>icons/128x128/edit-redo.png</file>
<file>icons/128x128/edit-rename.png</file>
<file>icons/128x128/edit-undo.png</file>
<file>icons/128x128/electrocompaniet.png</file>
<file>icons/128x128/equalizer.png</file>
<file>icons/128x128/folder-new.png</file>
<file>icons/128x128/folder.png</file>
<file>icons/128x128/folder-sound.png</file>
<file>icons/128x128/footsteps.png</file>
<file>icons/128x128/go-down.png</file>
<file>icons/128x128/go-home.png</file>
<file>icons/128x128/go-jump.png</file>
<file>icons/128x128/go-next.png</file>
<file>icons/128x128/go-previous.png</file>
<file>icons/128x128/go-up.png</file>
<file>icons/128x128/gstreamer.png</file>
<file>icons/128x128/guitar.png</file>
<file>icons/128x128/headset.png</file>
<file>icons/128x128/help-hint.png</file>
<file>icons/128x128/intel.png</file>
<file>icons/128x128/jack.png</file>
<file>icons/128x128/keyboard.png</file>
<file>icons/128x128/list-add.png</file>
<file>icons/128x128/list-remove.png</file>
<file>icons/128x128/mcintosh-player.png</file>
<file>icons/128x128/mcintosh-text.png</file>
<file>icons/128x128/media-eject.png</file>
<file>icons/128x128/media-forward.png</file>
<file>icons/128x128/media-pause.png</file>
<file>icons/128x128/media-play.png</file>
<file>icons/128x128/media-rewind.png</file>
<file>icons/128x128/media-stop.png</file>
<file>icons/128x128/nvidia.png</file>
<file>icons/128x128/play2.png</file>
<file>icons/128x128/realtek.png</file>
<file>icons/128x128/search.png</file>
<file>icons/128x128/soundcard2.png</file>
<file>icons/128x128/soundcard.png</file>
<file>icons/128x128/speaker.png</file>
<file>icons/128x128/star-grey.png</file>
<file>icons/128x128/star.png</file>
<file>icons/128x128/strawberry-panel-grey.png</file>
<file>icons/128x128/strawberry-panel.png</file>
<file>icons/128x128/strawberry.png</file>
<file>icons/128x128/strawberry.svg</file>
<file>icons/128x128/tools-wizard.png</file>
<file>icons/128x128/view-choose.png</file>
<file>icons/128x128/view-fullscreen.png</file>
<file>icons/128x128/view-media-lyrics.png</file>
<file>icons/128x128/view-media-playlist.png</file>
<file>icons/128x128/view-media-visualization.png</file>
<file>icons/128x128/view-refresh.png</file>
<file>icons/128x128/vinyl.png</file>
<file>icons/128x128/vlc.png</file>
<file>icons/128x128/xine.png</file>
<file>icons/128x128/zoom-in.png</file>
<file>icons/128x128/zoom-out.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
<file>icons/64x64/applications-internet.png</file>
<file>icons/64x64/bluetooth.png</file>
<file>icons/64x64/cdcase.png</file>
<file>icons/64x64/cd.png</file>
<file>icons/64x64/configure.png</file>
<file>icons/64x64/device-ipod-nano.png</file>
<file>icons/64x64/device-ipod.png</file>
<file>icons/64x64/device-phone.png</file>
<file>icons/64x64/device.png</file>
<file>icons/64x64/device-usb-drive.png</file>
<file>icons/64x64/device-usb-flash.png</file>
<file>icons/64x64/dialog-error.png</file>
<file>icons/64x64/dialog-information.png</file>
<file>icons/64x64/dialog-ok-apply.png</file>
<file>icons/64x64/dialog-password.png</file>
<file>icons/64x64/dialog-warning.png</file>
<file>icons/64x64/document-download.png</file>
<file>icons/64x64/document-new.png</file>
<file>icons/64x64/document-open-folder.png</file>
<file>icons/64x64/document-open.png</file>
<file>icons/64x64/document-save.png</file>
<file>icons/64x64/document-search.png</file>
<file>icons/64x64/download.png</file>
<file>icons/64x64/edit-clear-list.png</file>
<file>icons/64x64/edit-clear-locationbar-ltr.png</file>
<file>icons/64x64/edit-copy.png</file>
<file>icons/64x64/edit-delete.png</file>
<file>icons/64x64/edit-find.png</file>
<file>icons/64x64/edit-redo.png</file>
<file>icons/64x64/edit-rename.png</file>
<file>icons/64x64/edit-undo.png</file>
<file>icons/64x64/electrocompaniet.png</file>
<file>icons/64x64/equalizer.png</file>
<file>icons/64x64/folder-new.png</file>
<file>icons/64x64/folder.png</file>
<file>icons/64x64/folder-sound.png</file>
<file>icons/64x64/footsteps.png</file>
<file>icons/64x64/go-down.png</file>
<file>icons/64x64/go-home.png</file>
<file>icons/64x64/go-jump.png</file>
<file>icons/64x64/go-next.png</file>
<file>icons/64x64/go-previous.png</file>
<file>icons/64x64/go-up.png</file>
<file>icons/64x64/gstreamer.png</file>
<file>icons/64x64/guitar.png</file>
<file>icons/64x64/headset.png</file>
<file>icons/64x64/help-hint.png</file>
<file>icons/64x64/intel.png</file>
<file>icons/64x64/jack.png</file>
<file>icons/64x64/keyboard.png</file>
<file>icons/64x64/list-add.png</file>
<file>icons/64x64/list-remove.png</file>
<file>icons/64x64/mcintosh-player.png</file>
<file>icons/64x64/mcintosh-text.png</file>
<file>icons/64x64/media-eject.png</file>
<file>icons/64x64/media-forward.png</file>
<file>icons/64x64/media-pause.png</file>
<file>icons/64x64/media-play.png</file>
<file>icons/64x64/media-rewind.png</file>
<file>icons/64x64/media-stop.png</file>
<file>icons/64x64/nvidia.png</file>
<file>icons/64x64/play2.png</file>
<file>icons/64x64/pulseaudio.png</file>
<file>icons/64x64/realtek.png</file>
<file>icons/64x64/search.png</file>
<file>icons/64x64/soundcard2.png</file>
<file>icons/64x64/soundcard.png</file>
<file>icons/64x64/speaker.png</file>
<file>icons/64x64/star-grey.png</file>
<file>icons/64x64/star.png</file>
<file>icons/64x64/strawberry-panel-grey.png</file>
<file>icons/64x64/strawberry-panel.png</file>
<file>icons/64x64/strawberry.png</file>
<file>icons/64x64/tools-wizard.png</file>
<file>icons/64x64/view-choose.png</file>
<file>icons/64x64/view-fullscreen.png</file>
<file>icons/64x64/view-media-lyrics.png</file>
<file>icons/64x64/view-media-playlist.png</file>
<file>icons/64x64/view-media-visualization.png</file>
<file>icons/64x64/view-refresh.png</file>
<file>icons/64x64/vinyl.png</file>
<file>icons/64x64/vlc.png</file>
<file>icons/64x64/xine.png</file>
<file>icons/64x64/zoom-in.png</file>
<file>icons/64x64/zoom-out.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
<file>icons/48x48/applications-internet.png</file>
<file>icons/48x48/bluetooth.png</file>
<file>icons/48x48/cdcase.png</file>
<file>icons/48x48/cd.png</file>
<file>icons/48x48/configure.png</file>
<file>icons/48x48/device-ipod-nano.png</file>
<file>icons/48x48/device-ipod.png</file>
<file>icons/48x48/device-phone.png</file>
<file>icons/48x48/device.png</file>
<file>icons/48x48/device-usb-drive.png</file>
<file>icons/48x48/device-usb-flash.png</file>
<file>icons/48x48/dialog-error.png</file>
<file>icons/48x48/dialog-information.png</file>
<file>icons/48x48/dialog-ok-apply.png</file>
<file>icons/48x48/dialog-password.png</file>
<file>icons/48x48/dialog-warning.png</file>
<file>icons/48x48/document-download.png</file>
<file>icons/48x48/document-new.png</file>
<file>icons/48x48/document-open-folder.png</file>
<file>icons/48x48/document-open.png</file>
<file>icons/48x48/document-save.png</file>
<file>icons/48x48/document-search.png</file>
<file>icons/48x48/download.png</file>
<file>icons/48x48/edit-clear-list.png</file>
<file>icons/48x48/edit-clear-locationbar-ltr.png</file>
<file>icons/48x48/edit-copy.png</file>
<file>icons/48x48/edit-delete.png</file>
<file>icons/48x48/edit-find.png</file>
<file>icons/48x48/edit-redo.png</file>
<file>icons/48x48/edit-rename.png</file>
<file>icons/48x48/edit-undo.png</file>
<file>icons/48x48/electrocompaniet.png</file>
<file>icons/48x48/equalizer.png</file>
<file>icons/48x48/folder-new.png</file>
<file>icons/48x48/folder.png</file>
<file>icons/48x48/folder-sound.png</file>
<file>icons/48x48/footsteps.png</file>
<file>icons/48x48/go-down.png</file>
<file>icons/48x48/go-home.png</file>
<file>icons/48x48/go-jump.png</file>
<file>icons/48x48/go-next.png</file>
<file>icons/48x48/go-previous.png</file>
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/gstreamer.png</file>
<file>icons/48x48/guitar.png</file>
<file>icons/48x48/headset.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/intel.png</file>
<file>icons/48x48/jack.png</file>
<file>icons/48x48/keyboard.png</file>
<file>icons/48x48/list-add.png</file>
<file>icons/48x48/list-remove.png</file>
<file>icons/48x48/mcintosh-player.png</file>
<file>icons/48x48/mcintosh.png</file>
<file>icons/48x48/mcintosh-text.png</file>
<file>icons/48x48/media-eject.png</file>
<file>icons/48x48/media-forward.png</file>
<file>icons/48x48/media-pause.png</file>
<file>icons/48x48/media-playlist-repeat.png</file>
<file>icons/48x48/media-playlist-shuffle.png</file>
<file>icons/48x48/media-play.png</file>
<file>icons/48x48/media-rewind.png</file>
<file>icons/48x48/media-stop.png</file>
<file>icons/48x48/nvidia.png</file>
<file>icons/48x48/play2.png</file>
<file>icons/48x48/pulseaudio.png</file>
<file>icons/48x48/realtek.png</file>
<file>icons/48x48/search.png</file>
<file>icons/48x48/soundcard2.png</file>
<file>icons/48x48/soundcard.png</file>
<file>icons/48x48/speaker.png</file>
<file>icons/48x48/star-grey.png</file>
<file>icons/48x48/star.png</file>
<file>icons/48x48/strawberry-panel-grey.png</file>
<file>icons/48x48/strawberry-panel.png</file>
<file>icons/48x48/strawberry.png</file>
<file>icons/48x48/tools-wizard.png</file>
<file>icons/48x48/view-choose.png</file>
<file>icons/48x48/view-fullscreen.png</file>
<file>icons/48x48/view-media-lyrics.png</file>
<file>icons/48x48/view-media-playlist.png</file>
<file>icons/48x48/view-media-visualization.png</file>
<file>icons/48x48/view-refresh.png</file>
<file>icons/48x48/vinyl.png</file>
<file>icons/48x48/vlc.png</file>
<file>icons/48x48/xine.png</file>
<file>icons/48x48/zoom-in.png</file>
<file>icons/48x48/zoom-out.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
<file>icons/32x32/applications-internet.png</file>
<file>icons/32x32/bluetooth.png</file>
<file>icons/32x32/cdcase.png</file>
<file>icons/32x32/cd.png</file>
<file>icons/32x32/configure.png</file>
<file>icons/32x32/device-ipod-nano.png</file>
<file>icons/32x32/device-ipod.png</file>
<file>icons/32x32/device-phone.png</file>
<file>icons/32x32/device.png</file>
<file>icons/32x32/device-usb-drive.png</file>
<file>icons/32x32/device-usb-flash.png</file>
<file>icons/32x32/dialog-error.png</file>
<file>icons/32x32/dialog-information.png</file>
<file>icons/32x32/dialog-ok-apply.png</file>
<file>icons/32x32/dialog-password.png</file>
<file>icons/32x32/dialog-warning.png</file>
<file>icons/32x32/document-download.png</file>
<file>icons/32x32/document-new.png</file>
<file>icons/32x32/document-open-folder.png</file>
<file>icons/32x32/document-open.png</file>
<file>icons/32x32/document-save.png</file>
<file>icons/32x32/document-search.png</file>
<file>icons/32x32/download.png</file>
<file>icons/32x32/edit-clear-list.png</file>
<file>icons/32x32/edit-clear-locationbar-ltr.png</file>
<file>icons/32x32/edit-copy.png</file>
<file>icons/32x32/edit-delete.png</file>
<file>icons/32x32/edit-find.png</file>
<file>icons/32x32/edit-redo.png</file>
<file>icons/32x32/edit-rename.png</file>
<file>icons/32x32/edit-undo.png</file>
<file>icons/32x32/electrocompaniet.png</file>
<file>icons/32x32/equalizer.png</file>
<file>icons/32x32/folder-new.png</file>
<file>icons/32x32/folder.png</file>
<file>icons/32x32/folder-sound.png</file>
<file>icons/32x32/footsteps.png</file>
<file>icons/32x32/go-down.png</file>
<file>icons/32x32/go-home.png</file>
<file>icons/32x32/go-jump.png</file>
<file>icons/32x32/go-next.png</file>
<file>icons/32x32/go-previous.png</file>
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/gstreamer.png</file>
<file>icons/32x32/guitar.png</file>
<file>icons/32x32/headset.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/intel.png</file>
<file>icons/32x32/jack.png</file>
<file>icons/32x32/keyboard.png</file>
<file>icons/32x32/list-add.png</file>
<file>icons/32x32/list-remove.png</file>
<file>icons/32x32/mcintosh-player.png</file>
<file>icons/32x32/mcintosh.png</file>
<file>icons/32x32/mcintosh-text.png</file>
<file>icons/32x32/media-eject.png</file>
<file>icons/32x32/media-forward.png</file>
<file>icons/32x32/media-pause.png</file>
<file>icons/32x32/media-playlist-repeat.png</file>
<file>icons/32x32/media-playlist-shuffle.png</file>
<file>icons/32x32/media-play.png</file>
<file>icons/32x32/media-rewind.png</file>
<file>icons/32x32/media-stop.png</file>
<file>icons/32x32/nvidia.png</file>
<file>icons/32x32/play2.png</file>
<file>icons/32x32/pulseaudio.png</file>
<file>icons/32x32/realtek.png</file>
<file>icons/32x32/search.png</file>
<file>icons/32x32/soundcard2.png</file>
<file>icons/32x32/soundcard.png</file>
<file>icons/32x32/speaker.png</file>
<file>icons/32x32/star-grey.png</file>
<file>icons/32x32/star.png</file>
<file>icons/32x32/strawberry-panel-grey.png</file>
<file>icons/32x32/strawberry-panel.png</file>
<file>icons/32x32/strawberry.png</file>
<file>icons/32x32/strawberry.svg</file>
<file>icons/32x32/tools-wizard.png</file>
<file>icons/32x32/view-choose.png</file>
<file>icons/32x32/view-fullscreen.png</file>
<file>icons/32x32/view-media-lyrics.png</file>
<file>icons/32x32/view-media-playlist.png</file>
<file>icons/32x32/view-media-visualization.png</file>
<file>icons/32x32/view-refresh.png</file>
<file>icons/32x32/vinyl.png</file>
<file>icons/32x32/vlc.png</file>
<file>icons/32x32/xine.png</file>
<file>icons/32x32/zoom-in.png</file>
<file>icons/32x32/zoom-out.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
<file>icons/22x22/applications-internet.png</file>
<file>icons/22x22/bluetooth.png</file>
<file>icons/22x22/cdcase.png</file>
<file>icons/22x22/cd.png</file>
<file>icons/22x22/configure.png</file>
<file>icons/22x22/device-ipod-nano.png</file>
<file>icons/22x22/device-ipod.png</file>
<file>icons/22x22/device-phone.png</file>
<file>icons/22x22/device.png</file>
<file>icons/22x22/device-usb-drive.png</file>
<file>icons/22x22/device-usb-flash.png</file>
<file>icons/22x22/dialog-error.png</file>
<file>icons/22x22/dialog-information.png</file>
<file>icons/22x22/dialog-ok-apply.png</file>
<file>icons/22x22/dialog-password.png</file>
<file>icons/22x22/dialog-warning.png</file>
<file>icons/22x22/document-download.png</file>
<file>icons/22x22/document-new.png</file>
<file>icons/22x22/document-open-folder.png</file>
<file>icons/22x22/document-open.png</file>
<file>icons/22x22/document-save.png</file>
<file>icons/22x22/document-search.png</file>
<file>icons/22x22/download.png</file>
<file>icons/22x22/edit-clear-list.png</file>
<file>icons/22x22/edit-clear-locationbar-ltr.png</file>
<file>icons/22x22/edit-copy.png</file>
<file>icons/22x22/edit-delete.png</file>
<file>icons/22x22/edit-find.png</file>
<file>icons/22x22/edit-redo.png</file>
<file>icons/22x22/edit-rename.png</file>
<file>icons/22x22/edit-undo.png</file>
<file>icons/22x22/electrocompaniet.png</file>
<file>icons/22x22/equalizer.png</file>
<file>icons/22x22/folder-new.png</file>
<file>icons/22x22/folder.png</file>
<file>icons/22x22/folder-sound.png</file>
<file>icons/22x22/footsteps.png</file>
<file>icons/22x22/go-down.png</file>
<file>icons/22x22/go-home.png</file>
<file>icons/22x22/go-jump.png</file>
<file>icons/22x22/go-next.png</file>
<file>icons/22x22/go-previous.png</file>
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/gstreamer.png</file>
<file>icons/22x22/guitar.png</file>
<file>icons/22x22/headset.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/intel.png</file>
<file>icons/22x22/jack.png</file>
<file>icons/22x22/keyboard.png</file>
<file>icons/22x22/list-add.png</file>
<file>icons/22x22/list-remove.png</file>
<file>icons/22x22/mcintosh-player.png</file>
<file>icons/22x22/mcintosh.png</file>
<file>icons/22x22/mcintosh-text.png</file>
<file>icons/22x22/media-eject.png</file>
<file>icons/22x22/media-forward.png</file>
<file>icons/22x22/media-pause.png</file>
<file>icons/22x22/media-playlist-repeat.png</file>
<file>icons/22x22/media-playlist-shuffle.png</file>
<file>icons/22x22/media-play.png</file>
<file>icons/22x22/media-rewind.png</file>
<file>icons/22x22/media-stop.png</file>
<file>icons/22x22/nvidia.png</file>
<file>icons/22x22/play2.png</file>
<file>icons/22x22/pulseaudio.png</file>
<file>icons/22x22/realtek.png</file>
<file>icons/22x22/search.png</file>
<file>icons/22x22/soundcard2.png</file>
<file>icons/22x22/soundcard.png</file>
<file>icons/22x22/speaker.png</file>
<file>icons/22x22/star-grey.png</file>
<file>icons/22x22/star.png</file>
<file>icons/22x22/strawberry-panel-grey.png</file>
<file>icons/22x22/strawberry-panel.png</file>
<file>icons/22x22/strawberry.png</file>
<file>icons/22x22/strawberry.svg</file>
<file>icons/22x22/tools-wizard.png</file>
<file>icons/22x22/view-choose.png</file>
<file>icons/22x22/view-fullscreen.png</file>
<file>icons/22x22/view-media-lyrics.png</file>
<file>icons/22x22/view-media-playlist.png</file>
<file>icons/22x22/view-media-visualization.png</file>
<file>icons/22x22/view-refresh.png</file>
<file>icons/22x22/vinyl.png</file>
<file>icons/22x22/vlc.png</file>
<file>icons/22x22/xine.png</file>
<file>icons/22x22/zoom-in.png</file>
<file>icons/22x22/zoom-out.png</file>
<file>pictures/deezer.png</file>
<file>fonts/HumongousofEternitySt.ttf</file>
</qresource>
</RCC>

Binary file not shown.

View File

@@ -1,4 +1,444 @@
<RCC>
<qresource prefix="/">
</qresource>
<qresource prefix="/">
<file>icons/128x128/albums.png</file>
<file>icons/128x128/alsa.png</file>
<file>icons/128x128/application-exit.png</file>
<file>icons/128x128/applications-internet.png</file>
<file>icons/128x128/bluetooth.png</file>
<file>icons/128x128/cdcase.png</file>
<file>icons/128x128/cd.png</file>
<file>icons/128x128/configure.png</file>
<file>icons/128x128/device-ipod-nano.png</file>
<file>icons/128x128/device-ipod.png</file>
<file>icons/128x128/device-phone.png</file>
<file>icons/128x128/device.png</file>
<file>icons/128x128/device-usb-drive.png</file>
<file>icons/128x128/device-usb-flash.png</file>
<file>icons/128x128/dialog-error.png</file>
<file>icons/128x128/dialog-information.png</file>
<file>icons/128x128/dialog-ok-apply.png</file>
<file>icons/128x128/dialog-password.png</file>
<file>icons/128x128/dialog-warning.png</file>
<file>icons/128x128/document-download.png</file>
<file>icons/128x128/document-new.png</file>
<file>icons/128x128/document-open-folder.png</file>
<file>icons/128x128/document-open.png</file>
<file>icons/128x128/document-save.png</file>
<file>icons/128x128/document-search.png</file>
<file>icons/128x128/download.png</file>
<file>icons/128x128/edit-clear-list.png</file>
<file>icons/128x128/edit-clear-locationbar-ltr.png</file>
<file>icons/128x128/edit-copy.png</file>
<file>icons/128x128/edit-delete.png</file>
<file>icons/128x128/edit-find.png</file>
<file>icons/128x128/edit-redo.png</file>
<file>icons/128x128/edit-rename.png</file>
<file>icons/128x128/edit-undo.png</file>
<file>icons/128x128/electrocompaniet.png</file>
<file>icons/128x128/equalizer.png</file>
<file>icons/128x128/folder-new.png</file>
<file>icons/128x128/folder.png</file>
<file>icons/128x128/folder-sound.png</file>
<file>icons/128x128/footsteps.png</file>
<file>icons/128x128/go-down.png</file>
<file>icons/128x128/go-home.png</file>
<file>icons/128x128/go-jump.png</file>
<file>icons/128x128/go-next.png</file>
<file>icons/128x128/go-previous.png</file>
<file>icons/128x128/go-up.png</file>
<file>icons/128x128/gstreamer.png</file>
<file>icons/128x128/headset.png</file>
<file>icons/128x128/help-hint.png</file>
<file>icons/128x128/intel.png</file>
<file>icons/128x128/jack.png</file>
<file>icons/128x128/keyboard.png</file>
<file>icons/128x128/list-add.png</file>
<file>icons/128x128/list-remove.png</file>
<file>icons/128x128/mcintosh-player.png</file>
<file>icons/128x128/mcintosh-text.png</file>
<file>icons/128x128/media-eject.png</file>
<file>icons/128x128/media-forward.png</file>
<file>icons/128x128/media-pause.png</file>
<file>icons/128x128/media-play.png</file>
<file>icons/128x128/media-rewind.png</file>
<file>icons/128x128/media-stop.png</file>
<file>icons/128x128/nvidia.png</file>
<file>icons/128x128/play2.png</file>
<file>icons/128x128/realtek.png</file>
<file>icons/128x128/search.png</file>
<file>icons/128x128/soundcard.png</file>
<file>icons/128x128/speaker.png</file>
<file>icons/128x128/star-grey.png</file>
<file>icons/128x128/star.png</file>
<file>icons/128x128/strawberry.png</file>
<file>icons/128x128/strawberry.svg</file>
<file>icons/128x128/tools-wizard.png</file>
<file>icons/128x128/view-choose.png</file>
<file>icons/128x128/view-fullscreen.png</file>
<file>icons/128x128/view-media-lyrics.png</file>
<file>icons/128x128/view-media-playlist.png</file>
<file>icons/128x128/view-media-visualization.png</file>
<file>icons/128x128/view-refresh.png</file>
<file>icons/128x128/vinyl.png</file>
<file>icons/128x128/vlc.png</file>
<file>icons/128x128/xine.png</file>
<file>icons/128x128/zoom-in.png</file>
<file>icons/128x128/zoom-out.png</file>
<file>icons/128x128/tidal.png</file>
<file>icons/128x128/deezer.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
<file>icons/64x64/applications-internet.png</file>
<file>icons/64x64/bluetooth.png</file>
<file>icons/64x64/cdcase.png</file>
<file>icons/64x64/cd.png</file>
<file>icons/64x64/configure.png</file>
<file>icons/64x64/device-ipod-nano.png</file>
<file>icons/64x64/device-ipod.png</file>
<file>icons/64x64/device-phone.png</file>
<file>icons/64x64/device.png</file>
<file>icons/64x64/device-usb-drive.png</file>
<file>icons/64x64/device-usb-flash.png</file>
<file>icons/64x64/dialog-error.png</file>
<file>icons/64x64/dialog-information.png</file>
<file>icons/64x64/dialog-ok-apply.png</file>
<file>icons/64x64/dialog-password.png</file>
<file>icons/64x64/dialog-warning.png</file>
<file>icons/64x64/document-download.png</file>
<file>icons/64x64/document-new.png</file>
<file>icons/64x64/document-open-folder.png</file>
<file>icons/64x64/document-open.png</file>
<file>icons/64x64/document-save.png</file>
<file>icons/64x64/document-search.png</file>
<file>icons/64x64/download.png</file>
<file>icons/64x64/edit-clear-list.png</file>
<file>icons/64x64/edit-clear-locationbar-ltr.png</file>
<file>icons/64x64/edit-copy.png</file>
<file>icons/64x64/edit-delete.png</file>
<file>icons/64x64/edit-find.png</file>
<file>icons/64x64/edit-redo.png</file>
<file>icons/64x64/edit-rename.png</file>
<file>icons/64x64/edit-undo.png</file>
<file>icons/64x64/electrocompaniet.png</file>
<file>icons/64x64/equalizer.png</file>
<file>icons/64x64/folder-new.png</file>
<file>icons/64x64/folder.png</file>
<file>icons/64x64/folder-sound.png</file>
<file>icons/64x64/footsteps.png</file>
<file>icons/64x64/go-down.png</file>
<file>icons/64x64/go-home.png</file>
<file>icons/64x64/go-jump.png</file>
<file>icons/64x64/go-next.png</file>
<file>icons/64x64/go-previous.png</file>
<file>icons/64x64/go-up.png</file>
<file>icons/64x64/gstreamer.png</file>
<file>icons/64x64/headset.png</file>
<file>icons/64x64/help-hint.png</file>
<file>icons/64x64/intel.png</file>
<file>icons/64x64/jack.png</file>
<file>icons/64x64/keyboard.png</file>
<file>icons/64x64/list-add.png</file>
<file>icons/64x64/list-remove.png</file>
<file>icons/64x64/mcintosh-player.png</file>
<file>icons/64x64/mcintosh-text.png</file>
<file>icons/64x64/media-eject.png</file>
<file>icons/64x64/media-forward.png</file>
<file>icons/64x64/media-pause.png</file>
<file>icons/64x64/media-play.png</file>
<file>icons/64x64/media-rewind.png</file>
<file>icons/64x64/media-stop.png</file>
<file>icons/64x64/nvidia.png</file>
<file>icons/64x64/play2.png</file>
<file>icons/64x64/pulseaudio.png</file>
<file>icons/64x64/realtek.png</file>
<file>icons/64x64/search.png</file>
<file>icons/64x64/soundcard.png</file>
<file>icons/64x64/speaker.png</file>
<file>icons/64x64/star-grey.png</file>
<file>icons/64x64/star.png</file>
<file>icons/64x64/strawberry.png</file>
<file>icons/64x64/tools-wizard.png</file>
<file>icons/64x64/view-choose.png</file>
<file>icons/64x64/view-fullscreen.png</file>
<file>icons/64x64/view-media-lyrics.png</file>
<file>icons/64x64/view-media-playlist.png</file>
<file>icons/64x64/view-media-visualization.png</file>
<file>icons/64x64/view-refresh.png</file>
<file>icons/64x64/vinyl.png</file>
<file>icons/64x64/vlc.png</file>
<file>icons/64x64/xine.png</file>
<file>icons/64x64/zoom-in.png</file>
<file>icons/64x64/zoom-out.png</file>
<file>icons/64x64/tidal.png</file>
<file>icons/64x64/deezer.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
<file>icons/48x48/applications-internet.png</file>
<file>icons/48x48/bluetooth.png</file>
<file>icons/48x48/cdcase.png</file>
<file>icons/48x48/cd.png</file>
<file>icons/48x48/configure.png</file>
<file>icons/48x48/device-ipod-nano.png</file>
<file>icons/48x48/device-ipod.png</file>
<file>icons/48x48/device-phone.png</file>
<file>icons/48x48/device.png</file>
<file>icons/48x48/device-usb-drive.png</file>
<file>icons/48x48/device-usb-flash.png</file>
<file>icons/48x48/dialog-error.png</file>
<file>icons/48x48/dialog-information.png</file>
<file>icons/48x48/dialog-ok-apply.png</file>
<file>icons/48x48/dialog-password.png</file>
<file>icons/48x48/dialog-warning.png</file>
<file>icons/48x48/document-download.png</file>
<file>icons/48x48/document-new.png</file>
<file>icons/48x48/document-open-folder.png</file>
<file>icons/48x48/document-open.png</file>
<file>icons/48x48/document-save.png</file>
<file>icons/48x48/document-search.png</file>
<file>icons/48x48/download.png</file>
<file>icons/48x48/edit-clear-list.png</file>
<file>icons/48x48/edit-clear-locationbar-ltr.png</file>
<file>icons/48x48/edit-copy.png</file>
<file>icons/48x48/edit-delete.png</file>
<file>icons/48x48/edit-find.png</file>
<file>icons/48x48/edit-redo.png</file>
<file>icons/48x48/edit-rename.png</file>
<file>icons/48x48/edit-undo.png</file>
<file>icons/48x48/electrocompaniet.png</file>
<file>icons/48x48/equalizer.png</file>
<file>icons/48x48/folder-new.png</file>
<file>icons/48x48/folder.png</file>
<file>icons/48x48/folder-sound.png</file>
<file>icons/48x48/footsteps.png</file>
<file>icons/48x48/go-down.png</file>
<file>icons/48x48/go-home.png</file>
<file>icons/48x48/go-jump.png</file>
<file>icons/48x48/go-next.png</file>
<file>icons/48x48/go-previous.png</file>
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/gstreamer.png</file>
<file>icons/48x48/headset.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/intel.png</file>
<file>icons/48x48/jack.png</file>
<file>icons/48x48/keyboard.png</file>
<file>icons/48x48/list-add.png</file>
<file>icons/48x48/list-remove.png</file>
<file>icons/48x48/mcintosh-player.png</file>
<file>icons/48x48/mcintosh.png</file>
<file>icons/48x48/mcintosh-text.png</file>
<file>icons/48x48/media-eject.png</file>
<file>icons/48x48/media-forward.png</file>
<file>icons/48x48/media-pause.png</file>
<file>icons/48x48/media-playlist-repeat.png</file>
<file>icons/48x48/media-playlist-shuffle.png</file>
<file>icons/48x48/media-play.png</file>
<file>icons/48x48/media-rewind.png</file>
<file>icons/48x48/media-stop.png</file>
<file>icons/48x48/nvidia.png</file>
<file>icons/48x48/play2.png</file>
<file>icons/48x48/pulseaudio.png</file>
<file>icons/48x48/realtek.png</file>
<file>icons/48x48/search.png</file>
<file>icons/48x48/soundcard.png</file>
<file>icons/48x48/speaker.png</file>
<file>icons/48x48/star-grey.png</file>
<file>icons/48x48/star.png</file>
<file>icons/48x48/strawberry.png</file>
<file>icons/48x48/tools-wizard.png</file>
<file>icons/48x48/view-choose.png</file>
<file>icons/48x48/view-fullscreen.png</file>
<file>icons/48x48/view-media-lyrics.png</file>
<file>icons/48x48/view-media-playlist.png</file>
<file>icons/48x48/view-media-visualization.png</file>
<file>icons/48x48/view-refresh.png</file>
<file>icons/48x48/vinyl.png</file>
<file>icons/48x48/vlc.png</file>
<file>icons/48x48/xine.png</file>
<file>icons/48x48/zoom-in.png</file>
<file>icons/48x48/zoom-out.png</file>
<file>icons/48x48/tidal.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
<file>icons/32x32/applications-internet.png</file>
<file>icons/32x32/bluetooth.png</file>
<file>icons/32x32/cdcase.png</file>
<file>icons/32x32/cd.png</file>
<file>icons/32x32/configure.png</file>
<file>icons/32x32/device-ipod-nano.png</file>
<file>icons/32x32/device-ipod.png</file>
<file>icons/32x32/device-phone.png</file>
<file>icons/32x32/device.png</file>
<file>icons/32x32/device-usb-drive.png</file>
<file>icons/32x32/device-usb-flash.png</file>
<file>icons/32x32/dialog-error.png</file>
<file>icons/32x32/dialog-information.png</file>
<file>icons/32x32/dialog-ok-apply.png</file>
<file>icons/32x32/dialog-password.png</file>
<file>icons/32x32/dialog-warning.png</file>
<file>icons/32x32/document-download.png</file>
<file>icons/32x32/document-new.png</file>
<file>icons/32x32/document-open-folder.png</file>
<file>icons/32x32/document-open.png</file>
<file>icons/32x32/document-save.png</file>
<file>icons/32x32/document-search.png</file>
<file>icons/32x32/download.png</file>
<file>icons/32x32/edit-clear-list.png</file>
<file>icons/32x32/edit-clear-locationbar-ltr.png</file>
<file>icons/32x32/edit-copy.png</file>
<file>icons/32x32/edit-delete.png</file>
<file>icons/32x32/edit-find.png</file>
<file>icons/32x32/edit-redo.png</file>
<file>icons/32x32/edit-rename.png</file>
<file>icons/32x32/edit-undo.png</file>
<file>icons/32x32/electrocompaniet.png</file>
<file>icons/32x32/equalizer.png</file>
<file>icons/32x32/folder-new.png</file>
<file>icons/32x32/folder.png</file>
<file>icons/32x32/folder-sound.png</file>
<file>icons/32x32/footsteps.png</file>
<file>icons/32x32/go-down.png</file>
<file>icons/32x32/go-home.png</file>
<file>icons/32x32/go-jump.png</file>
<file>icons/32x32/go-next.png</file>
<file>icons/32x32/go-previous.png</file>
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/gstreamer.png</file>
<file>icons/32x32/headset.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/intel.png</file>
<file>icons/32x32/jack.png</file>
<file>icons/32x32/keyboard.png</file>
<file>icons/32x32/list-add.png</file>
<file>icons/32x32/list-remove.png</file>
<file>icons/32x32/mcintosh-player.png</file>
<file>icons/32x32/mcintosh.png</file>
<file>icons/32x32/mcintosh-text.png</file>
<file>icons/32x32/media-eject.png</file>
<file>icons/32x32/media-forward.png</file>
<file>icons/32x32/media-pause.png</file>
<file>icons/32x32/media-playlist-repeat.png</file>
<file>icons/32x32/media-playlist-shuffle.png</file>
<file>icons/32x32/media-play.png</file>
<file>icons/32x32/media-rewind.png</file>
<file>icons/32x32/media-stop.png</file>
<file>icons/32x32/nvidia.png</file>
<file>icons/32x32/play2.png</file>
<file>icons/32x32/pulseaudio.png</file>
<file>icons/32x32/realtek.png</file>
<file>icons/32x32/search.png</file>
<file>icons/32x32/soundcard.png</file>
<file>icons/32x32/speaker.png</file>
<file>icons/32x32/star-grey.png</file>
<file>icons/32x32/star.png</file>
<file>icons/32x32/strawberry.png</file>
<file>icons/32x32/strawberry.svg</file>
<file>icons/32x32/tools-wizard.png</file>
<file>icons/32x32/view-choose.png</file>
<file>icons/32x32/view-fullscreen.png</file>
<file>icons/32x32/view-media-lyrics.png</file>
<file>icons/32x32/view-media-playlist.png</file>
<file>icons/32x32/view-media-visualization.png</file>
<file>icons/32x32/view-refresh.png</file>
<file>icons/32x32/vinyl.png</file>
<file>icons/32x32/vlc.png</file>
<file>icons/32x32/xine.png</file>
<file>icons/32x32/zoom-in.png</file>
<file>icons/32x32/zoom-out.png</file>
<file>icons/32x32/tidal.png</file>
<file>icons/32x32/deezer.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
<file>icons/22x22/applications-internet.png</file>
<file>icons/22x22/bluetooth.png</file>
<file>icons/22x22/cdcase.png</file>
<file>icons/22x22/cd.png</file>
<file>icons/22x22/configure.png</file>
<file>icons/22x22/device-ipod-nano.png</file>
<file>icons/22x22/device-ipod.png</file>
<file>icons/22x22/device-phone.png</file>
<file>icons/22x22/device.png</file>
<file>icons/22x22/device-usb-drive.png</file>
<file>icons/22x22/device-usb-flash.png</file>
<file>icons/22x22/dialog-error.png</file>
<file>icons/22x22/dialog-information.png</file>
<file>icons/22x22/dialog-ok-apply.png</file>
<file>icons/22x22/dialog-password.png</file>
<file>icons/22x22/dialog-warning.png</file>
<file>icons/22x22/document-download.png</file>
<file>icons/22x22/document-new.png</file>
<file>icons/22x22/document-open-folder.png</file>
<file>icons/22x22/document-open.png</file>
<file>icons/22x22/document-save.png</file>
<file>icons/22x22/document-search.png</file>
<file>icons/22x22/download.png</file>
<file>icons/22x22/edit-clear-list.png</file>
<file>icons/22x22/edit-clear-locationbar-ltr.png</file>
<file>icons/22x22/edit-copy.png</file>
<file>icons/22x22/edit-delete.png</file>
<file>icons/22x22/edit-find.png</file>
<file>icons/22x22/edit-redo.png</file>
<file>icons/22x22/edit-rename.png</file>
<file>icons/22x22/edit-undo.png</file>
<file>icons/22x22/electrocompaniet.png</file>
<file>icons/22x22/equalizer.png</file>
<file>icons/22x22/folder-new.png</file>
<file>icons/22x22/folder.png</file>
<file>icons/22x22/folder-sound.png</file>
<file>icons/22x22/footsteps.png</file>
<file>icons/22x22/go-down.png</file>
<file>icons/22x22/go-home.png</file>
<file>icons/22x22/go-jump.png</file>
<file>icons/22x22/go-next.png</file>
<file>icons/22x22/go-previous.png</file>
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/gstreamer.png</file>
<file>icons/22x22/headset.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/intel.png</file>
<file>icons/22x22/jack.png</file>
<file>icons/22x22/keyboard.png</file>
<file>icons/22x22/list-add.png</file>
<file>icons/22x22/list-remove.png</file>
<file>icons/22x22/mcintosh-player.png</file>
<file>icons/22x22/mcintosh.png</file>
<file>icons/22x22/mcintosh-text.png</file>
<file>icons/22x22/media-eject.png</file>
<file>icons/22x22/media-forward.png</file>
<file>icons/22x22/media-pause.png</file>
<file>icons/22x22/media-playlist-repeat.png</file>
<file>icons/22x22/media-playlist-shuffle.png</file>
<file>icons/22x22/media-play.png</file>
<file>icons/22x22/media-rewind.png</file>
<file>icons/22x22/media-stop.png</file>
<file>icons/22x22/nvidia.png</file>
<file>icons/22x22/play2.png</file>
<file>icons/22x22/pulseaudio.png</file>
<file>icons/22x22/realtek.png</file>
<file>icons/22x22/search.png</file>
<file>icons/22x22/soundcard.png</file>
<file>icons/22x22/speaker.png</file>
<file>icons/22x22/star-grey.png</file>
<file>icons/22x22/star.png</file>
<file>icons/22x22/strawberry.png</file>
<file>icons/22x22/strawberry.svg</file>
<file>icons/22x22/tools-wizard.png</file>
<file>icons/22x22/view-choose.png</file>
<file>icons/22x22/view-fullscreen.png</file>
<file>icons/22x22/view-media-lyrics.png</file>
<file>icons/22x22/view-media-playlist.png</file>
<file>icons/22x22/view-media-visualization.png</file>
<file>icons/22x22/view-refresh.png</file>
<file>icons/22x22/vinyl.png</file>
<file>icons/22x22/vlc.png</file>
<file>icons/22x22/xine.png</file>
<file>icons/22x22/zoom-in.png</file>
<file>icons/22x22/zoom-out.png</file>
<file>icons/22x22/tidal.png</file>
<file>icons/22x22/deezer.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
data/icons/22x22/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
data/icons/22x22/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

BIN
data/icons/32x32/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

BIN
data/icons/32x32/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
data/icons/48x48/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Some files were not shown because too many files have changed in this diff Show More