Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b782a2c8a2 | ||
|
|
298783e2c5 | ||
|
|
bc9ec8025c | ||
|
|
26459763e5 | ||
|
|
1213306657 | ||
|
|
50add12e4b | ||
|
|
67c889f982 | ||
|
|
08cba25071 | ||
|
|
ff35b01bac | ||
|
|
faee1977fe | ||
|
|
6105b99a7f | ||
|
|
4993201b70 | ||
|
|
f456ca674d | ||
|
|
2ba350f76f | ||
|
|
3fe92a62ac | ||
|
|
f4dcf6821f | ||
|
|
0c10013858 | ||
|
|
3e9530fa8d | ||
|
|
0f4ffe4fce | ||
|
|
e1c01e5d25 | ||
|
|
51021131d7 | ||
|
|
89a08d1d5e | ||
|
|
ba8717f95a | ||
|
|
c8dfb9b0db | ||
|
|
3a02ece169 | ||
|
|
262df6b461 | ||
|
|
b9516fdfd4 | ||
|
|
9de41bc027 | ||
|
|
53b5cf3855 | ||
|
|
0567358783 | ||
|
|
c97bc55c6f | ||
|
|
3ef0bf60d0 | ||
|
|
b7b8084a38 | ||
|
|
5221f13498 | ||
|
|
0c0a8d70f3 | ||
|
|
2ff971878d | ||
|
|
1a0dc1e614 | ||
|
|
4a0bd99654 | ||
|
|
5cb98e44cb | ||
|
|
13ed99b9c3 | ||
|
|
0cda4e27aa | ||
|
|
0969e7f504 | ||
|
|
cad73e18e2 | ||
|
|
9eadeddfd9 | ||
|
|
de11cb173b | ||
|
|
5853bc68d1 | ||
|
|
7d1fd9d46f | ||
|
|
c977c822d5 | ||
|
|
c05fb33ea2 | ||
|
|
b9d0b3e152 | ||
|
|
a9e905b301 | ||
|
|
a8a714c820 | ||
|
|
9349ad9383 | ||
|
|
f686f00951 | ||
|
|
3d13c12cb7 | ||
|
|
2384a42d33 | ||
|
|
f507fec905 | ||
|
|
83a9724d17 | ||
|
|
4156e26f76 | ||
|
|
6d269e1786 | ||
|
|
ea447cab37 | ||
|
|
4f3e7de441 | ||
|
|
0a81fa99fc | ||
|
|
4aad44cb62 | ||
|
|
69dda39d02 | ||
|
|
ca3ba6f136 | ||
|
|
044cf4624a | ||
|
|
1fbfabdf66 | ||
|
|
db035351be | ||
|
|
2883ef840e | ||
|
|
8254ee911d | ||
|
|
560bc0a150 | ||
|
|
827898cd38 | ||
|
|
184dec146c | ||
|
|
298dbe96c8 | ||
|
|
6d888eb51a | ||
|
|
3694765611 | ||
|
|
b07ae3d34e | ||
|
|
64bcdf4734 | ||
|
|
1c23756fc4 | ||
|
|
50e3eeaafd | ||
|
|
843f528ebc | ||
|
|
faa0076988 | ||
|
|
59622c52ad | ||
|
|
a8e9aba58b | ||
|
|
36563cd1e1 | ||
|
|
072e712f0d | ||
|
|
121a186160 | ||
|
|
15a2ccc21e | ||
|
|
dbd8ea69eb | ||
|
|
8a57356f64 | ||
|
|
c77cb002f3 | ||
|
|
aa83a2b40b | ||
|
|
65b04cac6e | ||
|
|
5e577190a8 | ||
|
|
0143617056 | ||
|
|
a77dde7d3b | ||
|
|
7dcdb7c673 | ||
|
|
6de8eb56cd | ||
|
|
04e272d9bc | ||
|
|
17fe201473 | ||
|
|
25249be37f | ||
|
|
97ec12b5b3 | ||
|
|
246f82bfad | ||
|
|
db5679bbe9 | ||
|
|
feb0e1c45b | ||
|
|
edba837295 | ||
|
|
55882360ef | ||
|
|
6039370ad6 | ||
|
|
2d238c08d3 | ||
|
|
9b337b6a34 | ||
|
|
370db791aa | ||
|
|
9e3c547580 | ||
|
|
ab5d9b62b8 | ||
|
|
8e35e0c476 | ||
|
|
9d9492b528 | ||
|
|
9732cc2ce2 | ||
|
|
a4beea3f34 | ||
|
|
c9256c52bf | ||
|
|
6563bec7e4 | ||
|
|
072facdf7b | ||
|
|
a0f07a7a67 | ||
|
|
1a7465ba94 | ||
|
|
be3862ec40 | ||
|
|
a5276a3b7e | ||
|
|
fc8a27f55b | ||
|
|
87718bee24 | ||
|
|
56f2e00990 | ||
|
|
27e3448dda | ||
|
|
9404e40cad | ||
|
|
982f399aff | ||
|
|
6d373737db | ||
|
|
7f9e196234 | ||
|
|
95d03de160 | ||
|
|
d43190a41f | ||
|
|
b5c0529969 | ||
|
|
621a5b1de8 | ||
|
|
e30f269412 | ||
|
|
494ac20cca | ||
|
|
bf997a6d2e | ||
|
|
bc0c0b7950 | ||
|
|
f202cf6988 | ||
|
|
e62fb964ff | ||
|
|
9014781336 | ||
|
|
e479e7e113 | ||
|
|
f9379961e9 | ||
|
|
e5e6cbf6e4 | ||
|
|
6d686ee66a | ||
|
|
19b645d731 | ||
|
|
28c685dcd8 | ||
|
|
0abeefd470 | ||
|
|
1562585561 | ||
|
|
0a64a2a394 | ||
|
|
440a223bfb | ||
|
|
36b0a22c79 | ||
|
|
032022c246 | ||
|
|
9e4f3f9867 | ||
|
|
1119c87b2f | ||
|
|
36ab26c49a | ||
|
|
460cddb3dc | ||
|
|
a5c2dfacf0 | ||
|
|
b9788ef4b5 | ||
|
|
4a124e596e | ||
|
|
994a400ac9 | ||
|
|
d08e6a1dca | ||
|
|
154136185b | ||
|
|
f86b10c71f | ||
|
|
0b3d84a65e | ||
|
|
ee78b6f2bb | ||
|
|
521d5cf4fa | ||
|
|
52cf4412c8 | ||
|
|
dcae67ac7b | ||
|
|
cd0ee282c6 | ||
|
|
9d7e5864de | ||
|
|
d426eb2e07 | ||
|
|
06bed7feb7 | ||
|
|
adc38c4b12 | ||
|
|
5af58c19ae | ||
|
|
ac6cac8da1 | ||
|
|
3b30e66e87 | ||
|
|
41b0b1efd4 | ||
|
|
099d098dc7 | ||
|
|
1a55b7f1b2 | ||
|
|
f5ba8da3c7 | ||
|
|
08fcedd925 | ||
|
|
57f6f40e7d | ||
|
|
4ca99dde43 | ||
|
|
c518e42e18 | ||
|
|
0c329e6d83 | ||
|
|
820124f9e1 | ||
|
|
26062bd07b | ||
|
|
73029ab7a2 | ||
|
|
c3e916d945 | ||
|
|
6ee9f9d1ad | ||
|
|
b2c26eb4ed | ||
|
|
e181b47e3f | ||
|
|
dc91f19f30 | ||
|
|
e260fc5057 | ||
|
|
2368fff243 | ||
|
|
70db0a33d1 | ||
|
|
56f47909f4 | ||
|
|
e22b47a9d1 | ||
|
|
e32ed02a24 | ||
|
|
eb5d72a940 | ||
|
|
cbd809621a | ||
|
|
ad5d5d0ecd | ||
|
|
6bc948453c | ||
|
|
803590daa8 | ||
|
|
c63399ee98 | ||
|
|
f5ff95dca4 | ||
|
|
998357c0bb | ||
|
|
b43331bc3c | ||
|
|
ecfeb17869 | ||
|
|
9d2c9c732e | ||
|
|
6478fadedc | ||
|
|
a62eaa919d | ||
|
|
328a86288c | ||
|
|
f1902a5b63 | ||
|
|
693bade5a6 | ||
|
|
ca2acb177a | ||
|
|
670cd4e081 | ||
|
|
3a228c42bb | ||
|
|
73fd87f8aa | ||
|
|
3adc1b55fa | ||
|
|
0fd31f3632 | ||
|
|
55e0255fc2 | ||
|
|
8d23f6c422 | ||
|
|
8aebfdc88c | ||
|
|
a554032823 | ||
|
|
c818ce19e9 | ||
|
|
602f9759bb | ||
|
|
a00b8b2dca | ||
|
|
6dccc8857b | ||
|
|
b0f86a38ca | ||
|
|
1e4088b3e5 | ||
|
|
3c5da3c8bd | ||
|
|
8e9bf2653a | ||
|
|
0d6f377664 | ||
|
|
d30a63f79b | ||
|
|
ab3569a285 | ||
|
|
efdaf57f99 | ||
|
|
ada7325a04 | ||
|
|
c4e75dea65 | ||
|
|
41ce19ab97 | ||
|
|
3894419b14 | ||
|
|
af03c05559 | ||
|
|
04f1d296ea | ||
|
|
67df8f2243 | ||
|
|
980d8a65a1 | ||
|
|
fc66e2e2c7 | ||
|
|
505c1feb42 | ||
|
|
985b91e5f4 | ||
|
|
ef7b95220c | ||
|
|
6978983dd3 | ||
|
|
008c39cd00 | ||
|
|
416beb6b8e | ||
|
|
c4e64b591d |
5
.gitignore
vendored
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
30
3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
vendored
Normal 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
|
||||
128
3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
vendored
Normal 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
|
||||
28
3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m
vendored
Normal 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];
|
||||
12
3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m
vendored
Normal 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];
|
||||
38
3rdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m
vendored
Normal 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
@@ -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
@@ -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
|
||||
25
3rdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
3rdparty/qocoa/CMakeLists.txt
vendored
@@ -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})
|
||||
|
||||
|
||||
17
3rdparty/qocoa/Qocoa.pro
vendored
@@ -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
|
||||
}
|
||||
8
3rdparty/qocoa/README.md
vendored
@@ -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.
|
||||
|
||||
[](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
|
||||

|
||||
|
||||
70
3rdparty/qocoa/gallery.cpp
vendored
@@ -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);
|
||||
}
|
||||
14
3rdparty/qocoa/gallery.h
vendored
@@ -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
|
||||
BIN
3rdparty/qocoa/gallery.png
vendored
|
Before Width: | Height: | Size: 41 KiB |
12
3rdparty/qocoa/main.cpp
vendored
@@ -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();
|
||||
}
|
||||
3
3rdparty/qocoa/qbutton.h
vendored
@@ -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
|
||||
};
|
||||
|
||||
8
3rdparty/qocoa/qbutton_mac.mm
vendored
@@ -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()
|
||||
|
||||
15
3rdparty/qocoa/qbutton_nonmac.cpp
vendored
@@ -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
|
||||
{
|
||||
|
||||
7
3rdparty/qocoa/qocoa_mac.h
vendored
@@ -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);
|
||||
|
||||
3
3rdparty/qocoa/qprogressindicatorspinning.h
vendored
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
50
3rdparty/qocoa/qsearchfield.h
vendored
@@ -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
|
||||
|
||||
329
3rdparty/qocoa/qsearchfield_mac.mm
vendored
@@ -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);
|
||||
}
|
||||
|
||||
229
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
@@ -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);
|
||||
}
|
||||
|
||||
7
3rdparty/qocoa/qsearchfield_nonmac.qrc
vendored
Normal 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>
|
||||
BIN
3rdparty/qocoa/qsearchfield_nonmac_clear.png
vendored
Normal file
|
After Width: | Height: | Size: 736 B |
BIN
3rdparty/qocoa/qsearchfield_nonmac_magnifier.png
vendored
Normal file
|
After Width: | Height: | Size: 300 B |
BIN
3rdparty/qocoa/qsearchfield_nonmac_magnifier_menu.png
vendored
Normal file
|
After Width: | Height: | Size: 439 B |
2
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
@@ -27,3 +27,5 @@ ADD_LIBRARY(qtsingleapplication STATIC
|
||||
)
|
||||
|
||||
target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR}/src)
|
||||
|
||||
2
3rdparty/qtsingleapplication/qtlockedfile.h
vendored
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#ifndef QTSINGLECOREAPPLICATION_H
|
||||
#define QTSINGLECOREAPPLICATION_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
14
3rdparty/qtwin/CMakeLists.txt
vendored
@@ -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
|
||||
)
|
||||
229
3rdparty/qtwin/qtwin.cpp
vendored
@@ -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 ®ion)
|
||||
{
|
||||
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
|
||||
38
3rdparty/qtwin/qtwin.h
vendored
@@ -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
|
||||
9
3rdparty/qxt/CMakeLists.txt
vendored
@@ -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)
|
||||
|
||||
12
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
@@ -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)
|
||||
|
||||
4
3rdparty/qxt/qxtglobalshortcut_p.h
vendored
@@ -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);
|
||||
|
||||
|
||||
4
3rdparty/sha2/sha2.cpp
vendored
@@ -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
|
||||
|
||||
4
3rdparty/sha2/sha2.h
vendored
@@ -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
|
||||
|
||||
20
3rdparty/taglib/CMakeLists.txt
vendored
@@ -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
|
||||
|
||||
6
3rdparty/taglib/audioproperties.cpp
vendored
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
120
3rdparty/taglib/dsdiff/dsdiffproperties.cpp
vendored
Normal 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;
|
||||
}
|
||||
|
||||
83
3rdparty/taglib/dsdiff/dsdiffproperties.h
vendored
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
17
3rdparty/taglib/fileref.cpp
vendored
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
14
3rdparty/taglib/ogg/flac/oggflacfile.cpp
vendored
@@ -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);
|
||||
}
|
||||
|
||||
14
3rdparty/taglib/toolkit/tfile.cpp
vendored
@@ -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);
|
||||
}
|
||||
|
||||
41
3rdparty/taglib/toolkit/tfilestream.cpp
vendored
@@ -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
|
||||
}
|
||||
|
||||
5
3rdparty/taglib/toolkit/tfilestream.h
vendored
@@ -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.
|
||||
*/
|
||||
|
||||
198
CMakeLists.txt
@@ -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()
|
||||
|
||||
72
Changelog
@@ -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
@@ -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
|
||||
79
README.md
@@ -1,55 +1,67 @@
|
||||
Strawberry Music Player
|
||||
:strawberry: Strawberry Music Player [](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
|
||||
|
||||
|
||||

|
||||
|
||||
6
cmake/Deb.cmake
Normal 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}
|
||||
)
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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}")
|
||||
|
||||
460
data/data.qrc
@@ -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>
|
||||
|
||||
BIN
data/fonts/HumongousofEternitySt.ttf
Normal file
444
data/icons.qrc
@@ -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>
|
||||
|
||||
BIN
data/icons/128x128/deezer.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 22 KiB |
BIN
data/icons/128x128/tidal.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
data/icons/22x22/deezer.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
BIN
data/icons/22x22/tidal.png
Normal file
|
After Width: | Height: | Size: 933 B |
BIN
data/icons/32x32/deezer.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
BIN
data/icons/32x32/tidal.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
data/icons/48x48/deezer.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |