Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
bc78c3f3cb | ||
|
|
60b55b6d7d | ||
|
|
d45f8672cd | ||
|
|
8df599ffe5 | ||
|
|
f9c2801db1 | ||
|
|
e5774ffcdc | ||
|
|
aa4d8620f7 | ||
|
|
7b05bfd8b8 | ||
|
|
5065828515 | ||
|
|
eab25bbd17 | ||
|
|
6b1ae5d5ac | ||
|
|
e84681f93a | ||
|
|
7356344136 | ||
|
|
4746922e9f | ||
|
|
54c2ad13a9 |
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
3rdparty/qocoa/CMakeLists.txt
vendored
@@ -1,3 +1,6 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(SOURCES)
|
||||
|
||||
set(HEADERS
|
||||
@@ -21,12 +24,12 @@ else()
|
||||
qprogressindicatorspinning_nonmac.cpp
|
||||
)
|
||||
set(RESOURCES
|
||||
qsearchfield_nonmac.qrc
|
||||
qprogressindicatorspinning_nonmac.qrc
|
||||
)
|
||||
qt5_add_resources(RESOURCES_SOURCES ${RESOURCES})
|
||||
endif()
|
||||
|
||||
add_library(Qocoa STATIC
|
||||
${SOURCES} ${MOC_SOURCES} ${RESOURCES_SOURCES}
|
||||
)
|
||||
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:
|
||||
|
||||
19
3rdparty/qocoa/qsearchfield.h
vendored
@@ -2,22 +2,24 @@
|
||||
#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
|
||||
|
||||
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 reason);
|
||||
void setFocus(Qt::FocusReason);
|
||||
void setMenu(QMenu *menu);
|
||||
|
||||
public slots:
|
||||
void setText(const QString &text);
|
||||
@@ -31,15 +33,16 @@ signals:
|
||||
void editingFinished();
|
||||
void returnPressed();
|
||||
|
||||
private slots:
|
||||
void popupMenu();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent*);
|
||||
void resizeEvent(QResizeEvent*);
|
||||
bool eventFilter(QObject*, QEvent*);
|
||||
|
||||
private:
|
||||
friend class QSearchFieldPrivate;
|
||||
QPointer <QSearchFieldPrivate> pimpl;
|
||||
|
||||
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
|
||||
};
|
||||
|
||||
#endif // QSEARCHFIELD_H
|
||||
|
||||
124
3rdparty/qocoa/qsearchfield_mac.mm
vendored
@@ -29,8 +29,8 @@ THE SOFTWARE.
|
||||
#import "AppKit/NSSearchField.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QKeyEvent>
|
||||
#include <QClipboard>
|
||||
|
||||
class QSearchFieldPrivate : public QObject
|
||||
{
|
||||
@@ -95,6 +95,16 @@ public:
|
||||
pimpl->textDidChange(toQString([[notification object] stringValue]));
|
||||
}
|
||||
|
||||
-(void)controlTextDidEndEditing:(NSNotification*)notification {
|
||||
Q_UNUSED(notification);
|
||||
// No Q_ASSERT here as it is called on destruction.
|
||||
if (pimpl)
|
||||
pimpl->textDidEndEditing();
|
||||
|
||||
if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
|
||||
pimpl->returnPressed();
|
||||
}
|
||||
|
||||
-(BOOL)control: (NSControl *)control textView:
|
||||
(NSTextView *)textView doCommandBySelector:
|
||||
(SEL)commandSelector {
|
||||
@@ -111,16 +121,6 @@ public:
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(void)controlTextDidEndEditing:(NSNotification*)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();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface QocoaSearchField : NSSearchField
|
||||
@@ -129,14 +129,13 @@ 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) {
|
||||
|
||||
if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask)
|
||||
if ([event type] == NSEventTypeKeyDown && [event modifierFlags] & NSEventModifierFlagCommand)
|
||||
{
|
||||
QString keyString = toQString([event characters]);
|
||||
if (keyString == "a") // Cmd+a
|
||||
@@ -186,6 +185,25 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
void QSearchField::setMenu(QMenu *menu)
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
NSMenu *nsMenu = menu->macMenu();
|
||||
#else
|
||||
NSMenu *nsMenu = menu->toNSMenu();
|
||||
#endif
|
||||
|
||||
[[pimpl->nsSearchField cell] setSearchMenuTemplate:nsMenu];
|
||||
}
|
||||
|
||||
void QSearchField::popupMenu()
|
||||
{
|
||||
}
|
||||
|
||||
void QSearchField::setText(const QString &text)
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
@@ -194,10 +212,6 @@ void QSearchField::setText(const QString &text)
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -212,40 +226,6 @@ void QSearchField::setPlaceholderText(const QString &text)
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
QString QSearchField::placeholderText() const {
|
||||
Q_ASSERT(pimpl);
|
||||
NSString* placeholder = [[pimpl->nsSearchField cell] placeholderString];
|
||||
return toQString(placeholder);
|
||||
}
|
||||
|
||||
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).
|
||||
*/
|
||||
|
||||
// Q_ASSERT(pimpl);
|
||||
// if (!pimpl)
|
||||
// return;
|
||||
|
||||
// if ([pimpl->nsSearchField acceptsFirstResponder]) {
|
||||
// [[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField];
|
||||
// }
|
||||
}
|
||||
|
||||
void QSearchField::setFocus()
|
||||
{
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void QSearchField::clear()
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
@@ -274,12 +254,44 @@ QString QSearchField::text() const
|
||||
return toQString([pimpl->nsSearchField stringValue]);
|
||||
}
|
||||
|
||||
QString QSearchField::placeholderText() const
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return QString();
|
||||
|
||||
return toQString([[pimpl->nsSearchField cell] placeholderString]);
|
||||
}
|
||||
|
||||
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::changeEvent(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::EnabledChange) {
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
const bool enabled = isEnabled();
|
||||
[pimpl->nsSearchField setEnabled: enabled];
|
||||
}
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
|
||||
{
|
||||
QWidget::resizeEvent(resizeEvent);
|
||||
}
|
||||
|
||||
bool QSearchField::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
return QWidget::eventFilter(o, e);
|
||||
}
|
||||
|
||||
194
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
@@ -20,39 +20,48 @@ 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"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QToolButton>
|
||||
#include <QStyle>
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
class QSearchFieldPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
|
||||
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
|
||||
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton, QToolButton *searchButton)
|
||||
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton), searchButton(searchButton) {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int searchButtonPaddedWidth() const {
|
||||
return searchButton->width() + lineEditFrameWidth() * 2;
|
||||
}
|
||||
|
||||
int searchButtonPaddedHeight() const {
|
||||
return searchButton->height() + lineEditFrameWidth() * 2;
|
||||
}
|
||||
|
||||
QPointer<QLineEdit> lineEdit;
|
||||
QPointer<QToolButton> clearButton;
|
||||
QPointer<QToolButton> searchButton;
|
||||
QPointer<QMenu> searchMenu;
|
||||
};
|
||||
|
||||
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
|
||||
@@ -67,29 +76,94 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
|
||||
connect(lineEdit, SIGNAL(textChanged(QString)),
|
||||
this, SLOT(setText(QString)));
|
||||
|
||||
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
|
||||
|
||||
int iconsize = style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
QToolButton *clearButton = new QToolButton(this);
|
||||
QIcon clearIcon = QIcon::fromTheme(QLatin1String("edit-clear"),
|
||||
QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_clear.png")));
|
||||
clearButton->setIcon(clearIcon);
|
||||
clearButton->setIconSize(QSize(16, 16));
|
||||
clearButton->setStyleSheet("border: none; padding: 0px;");
|
||||
clearButton->resize(clearButton->sizeHint());
|
||||
clearButton->setIconSize(QSize(iconsize, iconsize));
|
||||
clearButton->setFixedSize(QSize(iconsize, iconsize));
|
||||
clearButton->setStyleSheet("border: none;");
|
||||
clearButton->hide();
|
||||
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
||||
|
||||
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
|
||||
QToolButton *searchButton = new QToolButton(this);
|
||||
QIcon searchIcon = QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png"));
|
||||
searchButton->setIcon(searchIcon);
|
||||
searchButton->setIconSize(QSize(iconsize, iconsize));
|
||||
searchButton->setFixedSize(QSize(iconsize, iconsize));
|
||||
searchButton->setStyleSheet("border: none;");
|
||||
searchButton->setPopupMode(QToolButton::InstantPopup);
|
||||
searchButton->setEnabled(false);
|
||||
connect(searchButton, SIGNAL(clicked()), this, SLOT(popupMenu()));
|
||||
|
||||
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton, searchButton);
|
||||
|
||||
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->setStyleSheet(QString("QLineEdit { padding-left: %1px; padding-right: %2px; } ")
|
||||
.arg(pimpl->searchButtonPaddedWidth())
|
||||
.arg(pimpl->clearButtonPaddedWidth()));
|
||||
const int width = qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth() + pimpl->searchButtonPaddedWidth());
|
||||
const int height = qMax(lineEdit->minimumSizeHint().height(),
|
||||
qMax(pimpl->clearButtonPaddedHeight(),
|
||||
pimpl->searchButtonPaddedHeight()));
|
||||
lineEdit->setMinimumSize(width, height);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(lineEdit);
|
||||
}
|
||||
|
||||
lineEdit->installEventFilter(this);
|
||||
void QSearchField::setMenu(QMenu *menu)
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
pimpl->searchMenu = menu;
|
||||
|
||||
QIcon searchIcon = menu ? QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier_menu.png"))
|
||||
: QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png"));
|
||||
pimpl->searchButton->setIcon(searchIcon);
|
||||
pimpl->searchButton->setEnabled(isEnabled() && menu);
|
||||
}
|
||||
|
||||
void QSearchField::popupMenu()
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
if (pimpl->searchMenu) {
|
||||
const QRect screenRect = qApp->desktop()->availableGeometry(pimpl->searchButton);
|
||||
const QSize sizeHint = pimpl->searchMenu->sizeHint();
|
||||
const QRect rect = pimpl->searchButton->rect();
|
||||
const int x = pimpl->searchButton->isRightToLeft()
|
||||
? rect.right() - sizeHint.width()
|
||||
: rect.left();
|
||||
const int y = pimpl->searchButton->mapToGlobal(QPoint(0, rect.bottom())).y() + sizeHint.height() <= screenRect.height()
|
||||
? rect.bottom()
|
||||
: rect.top() - sizeHint.height();
|
||||
QPoint point = pimpl->searchButton->mapToGlobal(QPoint(x, y));
|
||||
point.rx() = qMax(screenRect.left(), qMin(point.x(), screenRect.right() - sizeHint.width()));
|
||||
point.ry() += 1;
|
||||
|
||||
pimpl->searchMenu->popup(point);
|
||||
}
|
||||
}
|
||||
|
||||
void QSearchField::changeEvent(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::EnabledChange) {
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
const bool enabled = isEnabled();
|
||||
pimpl->searchButton->setEnabled(enabled && pimpl->searchMenu);
|
||||
pimpl->lineEdit->setEnabled(enabled);
|
||||
pimpl->clearButton->setEnabled(enabled);
|
||||
}
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
void QSearchField::setText(const QString &text)
|
||||
@@ -98,6 +172,8 @@ void QSearchField::setText(const QString &text)
|
||||
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
|
||||
return;
|
||||
|
||||
pimpl->clearButton->setVisible(!text.isEmpty());
|
||||
|
||||
if (text != this->text())
|
||||
pimpl->lineEdit->setText(text);
|
||||
}
|
||||
@@ -113,26 +189,6 @@ void QSearchField::setPlaceholderText(const QString &text)
|
||||
#endif
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void QSearchField::clear()
|
||||
{
|
||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
||||
@@ -160,6 +216,30 @@ QString QSearchField::text() const
|
||||
return pimpl->lineEdit->text();
|
||||
}
|
||||
|
||||
QString QSearchField::placeholderText() const {
|
||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
||||
if (!(pimpl && pimpl->lineEdit))
|
||||
return QString();
|
||||
|
||||
#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()
|
||||
{
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
|
||||
{
|
||||
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
|
||||
@@ -167,22 +247,10 @@ void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
|
||||
return;
|
||||
|
||||
QWidget::resizeEvent(resizeEvent);
|
||||
const int x = pimpl->lineEditFrameWidth();
|
||||
const int x = width() - pimpl->clearButtonPaddedWidth();
|
||||
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;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(o, e);
|
||||
pimpl->searchButton->move(pimpl->lineEditFrameWidth() * 2,
|
||||
(height() - pimpl->searchButton->height())/2);
|
||||
}
|
||||
|
||||
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 |
3
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(SINGLEAPP-SOURCES
|
||||
qtlocalpeer.cpp
|
||||
@@ -25,4 +26,4 @@ ADD_LIBRARY(qtsingleapplication STATIC
|
||||
${SINGLEAPP-SOURCES-MOC}
|
||||
)
|
||||
|
||||
QT5_USE_MODULES(qtsingleapplication Core Widgets Network)
|
||||
target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network)
|
||||
|
||||
1
3rdparty/qtwin/CMakeLists.txt
vendored
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(QTWIN-SOURCES
|
||||
qtwin.cpp
|
||||
|
||||
6
3rdparty/qtwin/qtwin.cpp
vendored
@@ -71,7 +71,7 @@ private:
|
||||
static bool resolveLibs()
|
||||
{
|
||||
if (!pDwmIsCompositionEnabled) {
|
||||
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||||
QLibrary dwmLib(QString::toLatin1("dwmapi"));
|
||||
pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
|
||||
pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
|
||||
pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow");
|
||||
@@ -165,7 +165,7 @@ bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int ri
|
||||
bool result = false;
|
||||
#ifdef Q_WS_WIN
|
||||
if (resolveLibs()) {
|
||||
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||||
QLibrary dwmLib(QString::toLatin1("dwmapi"));
|
||||
HRESULT hr = S_OK;
|
||||
MARGINS m = {left, top, right, bottom};
|
||||
hr = pDwmExtendFrameIntoClientArea(widget->winId(), &m);
|
||||
@@ -192,7 +192,7 @@ QColor QtWin::colorizatinColor()
|
||||
if (resolveLibs()) {
|
||||
DWORD color = 0;
|
||||
BOOL opaque = FALSE;
|
||||
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||||
QLibrary dwmLib(QString::toLatin1("dwmapi"));
|
||||
HRESULT hr = S_OK;
|
||||
hr = pDwmGetColorizationColor(&color, &opaque);
|
||||
if (SUCCEEDED(hr))
|
||||
|
||||
5
3rdparty/qxt/CMakeLists.txt
vendored
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(QXT-SOURCES
|
||||
qxtglobal.cpp
|
||||
@@ -29,7 +30,7 @@ ADD_LIBRARY(qxt STATIC
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
QT5_USE_MODULES(qxt Core Widgets)
|
||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
|
||||
else(WIN32)
|
||||
QT5_USE_MODULES(qxt Core Widgets X11Extras)
|
||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras)
|
||||
endif(WIN32)
|
||||
|
||||
1
3rdparty/sha2/CMakeLists.txt
vendored
@@ -1,3 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
add_library(sha2 STATIC sha2.cpp)
|
||||
|
||||
2
3rdparty/taglib/CMakeLists.txt
vendored
@@ -1,3 +1,5 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-delete-non-virtual-dtor")
|
||||
|
||||
set(TAGLIB_SOVERSION_CURRENT 17)
|
||||
|
||||
1
3rdparty/utf8-cpp/CMakeLists.txt
vendored
@@ -1 +1,2 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
324
CMakeLists.txt
@@ -19,6 +19,9 @@
|
||||
project(strawberry)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFiles)
|
||||
@@ -27,11 +30,22 @@ include(cmake/C++11Compat.cmake)
|
||||
include(cmake/Version.cmake)
|
||||
include(cmake/Summary.cmake)
|
||||
include(cmake/OptionalSource.cmake)
|
||||
include(cmake/ParseArguments.cmake)
|
||||
include(cmake/Rpm.cmake)
|
||||
|
||||
#set(CMAKE_BUILD_TYPE Debug)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(LINUX 1)
|
||||
endif()
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(FREEBSD 1)
|
||||
endif()
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
set(OPENBSD 1)
|
||||
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)
|
||||
@@ -42,11 +56,11 @@ endif(${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
|
||||
set(CMAKE_COMPILER_IS_CLANGXX 1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-uninitialized")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||
endif ()
|
||||
endif(APPLE)
|
||||
|
||||
find_program(CCACHE_EXECUTABLE NAMES ccache)
|
||||
if (CCACHE_EXECUTABLE)
|
||||
@@ -57,10 +71,6 @@ endif ()
|
||||
find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH)
|
||||
find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt5)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
set(LINUX 1)
|
||||
endif (UNIX AND NOT APPLE)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||
pkg_check_modules(GIO REQUIRED gio-2.0)
|
||||
@@ -72,47 +82,70 @@ find_package(Protobuf REQUIRED)
|
||||
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
|
||||
if(LINUX)
|
||||
find_package(ALSA REQUIRED)
|
||||
find_package(DBus REQUIRED)
|
||||
else(LINUX)
|
||||
find_package(ALSA)
|
||||
find_package(DBus)
|
||||
endif(LINUX)
|
||||
if(ALSA_FOUND)
|
||||
set(HAVE_ALSA ON)
|
||||
endif()
|
||||
find_package(X11)
|
||||
if(X11_FOUND)
|
||||
set(HAVE_X11 ON)
|
||||
endif()
|
||||
pkg_check_modules(GSTREAMER gstreamer-1.0)
|
||||
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
|
||||
pkg_check_modules(GSTREAMER_APP gstreamer-app-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(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)
|
||||
|
||||
if (WIN32)
|
||||
if(WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif (WIN32)
|
||||
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)
|
||||
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()
|
||||
if(NOT APPLE)
|
||||
find_package(Qt5 COMPONENTS WebKitWidgets)
|
||||
endif(NOT APPLE)
|
||||
if(DBUS_FOUND)
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus)
|
||||
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION)
|
||||
endif()
|
||||
if(APPLE)
|
||||
if(NOT QT_MAC_USE_COCOA)
|
||||
message(FATAL_ERROR "Cocoa support is required")
|
||||
endif(NOT QT_MAC_USE_COCOA)
|
||||
endif(APPLE)
|
||||
find_package(Qt5 REQUIRED COMPONENTS MacExtras)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
# 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)
|
||||
|
||||
# TAGLIB
|
||||
pkg_check_modules(TAGLIB taglib)
|
||||
@@ -146,138 +179,9 @@ if(LASTFM5_INCLUDE_DIRS AND LASTFM51_INCLUDE_DIRS)
|
||||
set(HAVE_LIBLASTFM1 ON)
|
||||
endif()
|
||||
|
||||
# CHROMAPRINT
|
||||
# CHECK INCLUDES
|
||||
CHECK_INCLUDE_FILES(chromaprint.h CHROMAPRINT_H)
|
||||
|
||||
if (APPLE)
|
||||
find_library(SPARKLE Sparkle)
|
||||
add_subdirectory(3rdparty/SPMediaKeyTap)
|
||||
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
|
||||
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
|
||||
endif (APPLE)
|
||||
|
||||
# Set up definitions and paths
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
||||
link_directories(${GSTREAMER_LIBRARY_DIRS})
|
||||
|
||||
# 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)
|
||||
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${LIBXML_INCLUDE_DIRS})
|
||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_PBUTILS_INCLUDE_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
# RC compiler
|
||||
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
|
||||
enable_language(RC)
|
||||
SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff -o <OBJECT> <SOURCE> -I ${CMAKE_SOURCE_DIR}/dist/windows")
|
||||
endif(WIN32)
|
||||
|
||||
add_definitions(-DQT_NO_CAST_TO_ASCII -DQT_STRICT_ITERATORS)
|
||||
|
||||
# Optional bits
|
||||
if(WIN32)
|
||||
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
|
||||
endif(WIN32)
|
||||
|
||||
optional_component(GSTREAMER ON "Engine: GStreamer backend"
|
||||
DEPENDS "gstreamer-1.0" GSTREAMER_FOUND
|
||||
DEPENDS "gstreamer-base-1.0" GSTREAMER_BASE_FOUND
|
||||
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"
|
||||
DEPENDS "libxine" LIBXINE_FOUND
|
||||
)
|
||||
|
||||
optional_component(VLC OFF "Engine: VLC backend"
|
||||
DEPENDS "libvlc" LIBVLC_FOUND
|
||||
)
|
||||
|
||||
optional_component(PHONON OFF "Engine: Phonon backend"
|
||||
DEPENDS "phonon4qt5" PHONON4QT5_FOUND
|
||||
)
|
||||
|
||||
optional_component(AUDIOCD ON "Devices: Audio CD support"
|
||||
DEPENDS "libcdio" CDIO_FOUND
|
||||
)
|
||||
|
||||
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 "Linux 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(LIBLASTFM ON "Last.fm support"
|
||||
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
optional_component(DBUS ON "D-Bus support"
|
||||
DEPENDS "Linux" LINUX
|
||||
)
|
||||
|
||||
optional_component(DEVICEKIT ON "Devices: DeviceKit backend"
|
||||
DEPENDS "D-Bus support" HAVE_DBUS
|
||||
)
|
||||
|
||||
optional_component(UDISKS2 ON "Devices: UDisks2 backend"
|
||||
DEPENDS "D-Bus support" HAVE_DBUS
|
||||
)
|
||||
|
||||
optional_component(SPARKLE ON "Sparkle integration"
|
||||
DEPENDS "Mac OS X" APPLE
|
||||
DEPENDS "Sparkle" SPARKLE
|
||||
)
|
||||
|
||||
optional_component(LIBPULSE ON "Pulse audio integration"
|
||||
DEPENDS "libpulse" LIBPULSE_FOUND
|
||||
)
|
||||
|
||||
if (HAVE_DBUS)
|
||||
find_package(Qt5 COMPONENTS DBus)
|
||||
get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION)
|
||||
endif ()
|
||||
|
||||
# We can include the Qt definitions now
|
||||
#include(${QT_USE_FILE})
|
||||
if(WIN32)
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::OpenGL Qt5::Sql Qt5::Network Qt5::Xml Qt5::Widgets Qt5::Concurrent)
|
||||
else(WIN32)
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::OpenGL Qt5::Sql Qt5::Network Qt5::Xml Qt5::Widgets Qt5::Concurrent Qt5::X11Extras Qt5::DBus)
|
||||
endif(WIN32)
|
||||
|
||||
# Remove GLU and GL from the link line - they're not really required and don't exist on my mingw toolchain
|
||||
list(REMOVE_ITEM QT_LIBRARIES "-lGLU -lGL")
|
||||
|
||||
# Use system sha2 if it's available
|
||||
find_path(SHA2_INCLUDE_DIRS sha2.h)
|
||||
find_library(SHA2_LIBRARIES sha2)
|
||||
@@ -326,17 +230,124 @@ else (USE_SYSTEM_QXT)
|
||||
endif (USE_SYSTEM_QXT)
|
||||
|
||||
# Qocoa
|
||||
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)
|
||||
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
|
||||
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
|
||||
endif (APPLE)
|
||||
|
||||
if (WIN32)
|
||||
# RC compiler
|
||||
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
|
||||
enable_language(RC)
|
||||
SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff -o <OBJECT> <SOURCE> -I ${CMAKE_SOURCE_DIR}/dist/windows")
|
||||
endif(WIN32)
|
||||
|
||||
# Optional bits
|
||||
if(WIN32)
|
||||
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
|
||||
endif(WIN32)
|
||||
|
||||
optional_component(DBUS ON "D-Bus support"
|
||||
DEPENDS "D-Bus" DBUS_FOUND
|
||||
)
|
||||
|
||||
optional_component(GSTREAMER ON "Engine: GStreamer backend"
|
||||
DEPENDS "gstreamer-1.0" GSTREAMER_FOUND
|
||||
DEPENDS "gstreamer-base-1.0" GSTREAMER_BASE_FOUND
|
||||
DEPENDS "gstreamer-app-1.0" GSTREAMER_APP_FOUND
|
||||
DEPENDS "gstreamer-audio-1.0" GSTREAMER_AUDIO_FOUND
|
||||
DEPENDS "gstreamer-tag-1.0" GSTREAMER_TAG_FOUND
|
||||
)
|
||||
|
||||
optional_component(XINE ON "Engine: Xine backend"
|
||||
DEPENDS "libxine" LIBXINE_FOUND
|
||||
)
|
||||
|
||||
optional_component(VLC ON "Engine: VLC backend"
|
||||
DEPENDS "libvlc" LIBVLC_FOUND
|
||||
)
|
||||
|
||||
optional_component(PHONON OFF "Engine: Phonon backend"
|
||||
DEPENDS "phonon4qt5" PHONON_FOUND
|
||||
)
|
||||
|
||||
optional_component(AUDIOCD ON "Devices: Audio CD support"
|
||||
DEPENDS "libcdio" CDIO_FOUND
|
||||
)
|
||||
|
||||
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(LIBLASTFM ON "Last.fm album cover provider"
|
||||
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
optional_component(DEVICEKIT ON "Devices: DeviceKit backend"
|
||||
DEPENDS "D-Bus support" DBUS_FOUND
|
||||
)
|
||||
|
||||
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(SPARKLE ON "Sparkle integration"
|
||||
DEPENDS "Mac OS X" APPLE
|
||||
DEPENDS "Sparkle" SPARKLE
|
||||
)
|
||||
|
||||
#if(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
|
||||
#add_subdirectory(ext/gstafc)
|
||||
#endif(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
|
||||
|
||||
# Set up definitions and paths
|
||||
|
||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
add_definitions(-DQT_USE_QSTRINGBUILDER)
|
||||
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
|
||||
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)
|
||||
endif()
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(src)
|
||||
if (WIN32)
|
||||
add_subdirectory(3rdparty/qtwin)
|
||||
endif (WIN32)
|
||||
add_subdirectory(dist)
|
||||
add_subdirectory(ext/libstrawberry-common)
|
||||
add_subdirectory(ext/libstrawberry-tagreader)
|
||||
@@ -353,3 +364,6 @@ 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!")
|
||||
endif()
|
||||
|
||||
22
Changelog
@@ -2,6 +2,28 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
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:
|
||||
* Fixed crash on exit caused by NVIDIA driver
|
||||
* Fixed PulseAudio device selection
|
||||
* Improvements to device selection
|
||||
|
||||
Version 0.1.5:
|
||||
* Makefile fixes for building
|
||||
|
||||
Version 0.1.4:
|
||||
* Fixed compliation with clang compiler
|
||||
* This release is mainly to get it working on openbsd and freebsd.
|
||||
|
||||
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
|
||||
|
||||
55
README.md
@@ -1,12 +1,10 @@
|
||||
Strawberry Music Player
|
||||
:strawberry: Strawberry Music Player
|
||||
=======================
|
||||
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:
|
||||
### :heavy_check_mark: Features:
|
||||
|
||||
* Play and organize music
|
||||
* Native desktop notifications
|
||||
@@ -17,39 +15,38 @@ It's written in C++ and Qt5. The name is inspired by the band Strawbs.
|
||||
* Support for multiple backends
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
|
||||
You can obtain and view the sourcecode on github at: https://github.com/jonaski/strawberry
|
||||
|
||||
It has so far been tested on Linux 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.
|
||||
It has so far been tested to work on Linux, OpenBSD and Windows (cross compiled using mingw).
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
### :heavy_exclamation_mark: Requirements
|
||||
|
||||
To build Strawberry from source you need the following installed on your system:
|
||||
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
||||
|
||||
* glib2, glib2-devel, git, cmake, make, gcc and gcc-c++
|
||||
* protobuf and development packages
|
||||
* boost development headers
|
||||
|
||||
* The following Qt5 components are required with additional development packages: Qt5Core, Qt5Widgets, Qt5Network, Qt5Sql, Qt5Xml, Qt5OpenGL, Qt5Concurrent, Qt5Test, 5X11Extras, Qt5WebKit, Qt5WebKitWidget and Qt5DBus.
|
||||
|
||||
* 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
|
||||
* [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, Widgets, Network, Sql, Xml, OpenGL, Concurrent, Test, WebKitWidget, 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/?)
|
||||
|
||||
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
|
||||
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
|
||||
|
||||
* 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.
|
||||
Optional:
|
||||
|
||||
* 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.
|
||||
|
||||
Compiling from source
|
||||
---------------------
|
||||
### :wrench: Compiling from source
|
||||
|
||||
### Get the code:
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
# Strawberry Music Player
|
||||
# Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
|
||||
#
|
||||
# Strawberry is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Strawberry 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
macro(add_engine engine_lower engine_upper lib_list src_list inc_list enabled)
|
||||
|
||||
#message(STATUS "ADD ENGINE: ${engine_lower} ${engine_upper} ${lib_list} ${src_list} ${inc_list} ${enabled}")
|
||||
|
||||
#set(ENGINE_LIBRARIES "")
|
||||
|
||||
# recreate list
|
||||
set(lib_list ${lib_list})
|
||||
#list(GET lib_list 0 name)
|
||||
|
||||
# add a user selectable build option
|
||||
option(ENGINE_${engine_upper}_ENABLED "enable engine ${engine_upper}" ${enabled})
|
||||
|
||||
# check if engine is enabled and needed librares are available
|
||||
if(ENGINE_${engine_upper}_ENABLED)
|
||||
|
||||
# check for all needed libraries
|
||||
foreach(lib ${lib_list})
|
||||
#pkg_check_modules(${lib} ${lib})
|
||||
if (NOT ${lib}_FOUND MATCHES 1)
|
||||
set(ENGINE_${engine_upper}_LIB_MISSING TRUE)
|
||||
endif(NOT ${lib}_FOUND MATCHES 1)
|
||||
endforeach(lib ${lib_list})
|
||||
|
||||
if(ENGINE_${engine_upper}_LIB_MISSING)
|
||||
set(ENGINES_MISSING "${ENGINES_MISSING} ${engine_lower}")
|
||||
#set("HAVE_${engine_upper}" 0 CACHE INTERNAL ${engine_upper})
|
||||
set("HAVE_${engine_upper}" OFF)
|
||||
else(ENGINE_${engine_upper}_LIB_MISSING)
|
||||
# add define -DHAVE_<engine> so we can clutter the code with #ifdefs
|
||||
#set("HAVE_${engine_upper}" 1 CACHE INTERNAL ${engine_upper})
|
||||
set("HAVE_${engine_upper}" ON)
|
||||
# add sources and headers
|
||||
list(APPEND SOURCES ${src_list})
|
||||
list(APPEND HEADERS ${inc_list})
|
||||
# add libraries to link against
|
||||
foreach(lib ${lib_list})
|
||||
#set(ENGINE_LIBRARIES ${ENGINE_LIBRARIES} ${${lib}_LIBRARIES} CACHE INTERNAL libraries)
|
||||
set(ENGINE_LIBRARIES ${ENGINE_LIBRARIES} ${${lib}_LIBRARIES})
|
||||
endforeach(lib ${lib_list})
|
||||
# add to list of enabled engines
|
||||
set(ENGINES_ENABLED "${ENGINES_ENABLED} ${engine_lower}")
|
||||
endif(ENGINE_${engine_upper}_LIB_MISSING)
|
||||
else(ENGINE_${engine_upper}_ENABLED)
|
||||
set(ENGINES_DISABLED "${ENGINES_DISABLED} ${engine_lower}")
|
||||
#set("HAVE_${engine_upper}" 0 CACHE INTERNAL ${engine_upper})
|
||||
set("HAVE_${engine_upper}" OFF)
|
||||
endif(ENGINE_${engine_upper}_ENABLED)
|
||||
|
||||
endmacro(add_engine engine_lower engine_upper lib_list src_list inc_list enabled)
|
||||
|
||||
# print engines to be built
|
||||
macro(print_engines)
|
||||
|
||||
if(ENGINES_ENABLED)
|
||||
message(STATUS "Building engines:${ENGINES_ENABLED}")
|
||||
endif(ENGINES_ENABLED)
|
||||
if(ENGINES_DISABLED)
|
||||
message(STATUS "Disabled engines:${ENGINES_DISABLED}")
|
||||
endif(ENGINES_DISABLED)
|
||||
if(ENGINES_MISSING)
|
||||
message(STATUS "Missing engines:${ENGINES_MISSING}")
|
||||
endif(ENGINES_MISSING)
|
||||
|
||||
#message(STATUS "Engine libraries:${ENGINE_LIBRARIES}")
|
||||
|
||||
# need at least 1 engine
|
||||
if(NOT ENGINES_ENABLED)
|
||||
message(FATAL_ERROR "No engine enabled!")
|
||||
endif(NOT ENGINES_ENABLED)
|
||||
|
||||
endmacro(print_engines)
|
||||
43
cmake/FindDBus.cmake
Normal file
@@ -0,0 +1,43 @@
|
||||
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)
|
||||
@@ -5,8 +5,8 @@ set(RPM_DISTRO suse CACHE STRING "Suffix of the rpm file")
|
||||
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
|
||||
|
||||
add_custom_target(rpm
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/maketarball.sh
|
||||
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/strawberry.spec
|
||||
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/strawberry.spec
|
||||
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/rpm/strawberry.spec
|
||||
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/rpm/strawberry.spec
|
||||
)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||
set(STRAWBERRY_VERSION_MINOR 1)
|
||||
set(STRAWBERRY_VERSION_PATCH 3)
|
||||
set(STRAWBERRY_VERSION_MINOR 2)
|
||||
set(STRAWBERRY_VERSION_PATCH 1)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
|
||||
if (WIN32)
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
endif()
|
||||
|
||||
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
||||
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
|
||||
@@ -22,52 +26,59 @@ if(STRAWBERRY_VERSION_PRERELEASE)
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${STRAWBERRY_VERSION_PACKAGE}${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
endif(STRAWBERRY_VERSION_PRERELEASE)
|
||||
|
||||
find_program(GIT_EXECUTABLE git)
|
||||
if(INCLUDE_GIT_REVISION)
|
||||
|
||||
find_program(GIT_EXECUTABLE git)
|
||||
if(GIT_EXECUTABLE-NOTFOUND)
|
||||
message(FATAL_ERROR "Missing GIT executable." )
|
||||
endif()
|
||||
|
||||
if(NOT GIT_EXECUTABLE-NOTFOUND)
|
||||
# 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
|
||||
)
|
||||
# Get the latest abbreviated commit hash of the working branch
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --tags --always
|
||||
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
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${GIT_INFO_RESULT} EQUAL 0)
|
||||
set(HAS_GIT_REVISION ON)
|
||||
if(NOT ${GIT_CMD_RESULT_REVISION} EQUAL 0)
|
||||
message(FATAL_ERROR "GIT command failed to get revision string '${GIT_REVISION}'")
|
||||
endif()
|
||||
|
||||
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}")
|
||||
|
||||
1009
data/data.qrc
|
Before Width: | Height: | Size: 26 KiB |
@@ -5,7 +5,7 @@
|
||||
}
|
||||
|
||||
#playlist[default_background_enabled = "true"] {
|
||||
background-image: url(:/pictures/strawbs-transparent.png);
|
||||
background-image: url(:pictures/strawbs-transparent.png);
|
||||
background-attachment: fixed;
|
||||
background-position: bottom right;
|
||||
background-repeat: none;
|
||||
|
||||
17
dist/CMakeLists.txt
vendored
@@ -1,14 +1,19 @@
|
||||
set(ENV{LC_ALL} "en_US.utf8")
|
||||
execute_process(COMMAND date "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/strawberry.spec @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/maketarball.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/rpm/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/rpm/strawberry.spec @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||
|
||||
if (UNIX)
|
||||
if (UNIX AND NOT APPLE)
|
||||
install(FILES ../data/icons/48x48/strawberry.png DESTINATION share/icons/hicolor/48x48/apps/)
|
||||
install(FILES ../data/icons/64x64/strawberry.png DESTINATION share/icons/hicolor/64x64/apps/)
|
||||
install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/)
|
||||
install(FILES ../data/icons/128x128/strawberry.svg DESTINATION share/icons/hicolor/scalable/apps/)
|
||||
install(FILES strawberry.desktop DESTINATION share/applications)
|
||||
install(FILES strawberry.1 strawberry-tagreader.1 DESTINATION share/man/man1)
|
||||
endif (UNIX)
|
||||
install(FILES unix/strawberry.desktop DESTINATION share/applications)
|
||||
install(FILES man/strawberry.1 man/strawberry-tagreader.1 DESTINATION share/man/man1)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
install(FILES macos/strawberry.icns DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
|
||||
endif()
|
||||
|
||||
235
dist/macos/Info.plist.in
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>strawberry</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Strawberry ${STRAWBERRY_VERSION_DISPLAY}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>strawberry</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.strawberry.strawberry</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${STRAWBERRY_VERSION_DISPLAY}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Strawberry</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${STRAWBERRY_VERSION_DISPLAY}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${STRAWBERRY_VERSION_PACKAGE}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.music</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7.0</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeOSTypes</key>
|
||||
<array>
|
||||
<string>****</string>
|
||||
<string>fold</string>
|
||||
<string>disk</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>xspf</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>Generic.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>application/xspf+xml</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>XSPF Playlist</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wav</string>
|
||||
</array>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/x-wav</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>WAVE Audio File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>pls</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>pls.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Shoutcast playlist</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>m3u</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>m3u.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/x-mpegurl</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Playlist file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>aac</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>mpeg4.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>AAC file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>ogg</string>
|
||||
<string>ogx</string>
|
||||
<string>ogm</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>ogg.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/ogg</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Ogg Vorbis File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>oga</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>ogg.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/ogg</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Ogg Audio File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wma</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>wma.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>WIndows Media Audio</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>mp3</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>mp3.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/mpeg</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>MPEG Audio Layer 3</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>3gp</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>generic.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>3GPP File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>m4a</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>mpeg4.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>MPEG-4 Audio File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>mpc</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>generic.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Musepack Audio File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>flac</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>generic.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>audio/flac</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>FLAC Audio File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
52
dist/macos/create-dmg.sh
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
# author: max@last.fm, muesli@tomahawk-player.org
|
||||
# brief: Produces a compressed DMG from a bundle directory
|
||||
# usage: Pass the bundle directory as the only parameter
|
||||
# note: This script depends on the Tomahawk build system, and must be run from
|
||||
# the build directory
|
||||
################################################################################
|
||||
|
||||
|
||||
#if [ -z $VERSION ]
|
||||
#then
|
||||
# echo VERSION must be set
|
||||
# exit 2
|
||||
#fi
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Please pass the bundle.app directory as the first parameter."
|
||||
exit 3
|
||||
fi
|
||||
################################################################################
|
||||
|
||||
|
||||
NAME=$(basename "$1" | perl -pe 's/(.*).app/\1/')
|
||||
IN="$1"
|
||||
TMP="dmg/$NAME"
|
||||
OUT="$NAME.dmg"
|
||||
mkdir -p "$TMP"
|
||||
################################################################################
|
||||
|
||||
# clean up
|
||||
rm -rf "$TMP"
|
||||
rm -f "$OUT"
|
||||
|
||||
# create DMG contents and copy files
|
||||
mkdir -p "$TMP/.background"
|
||||
#cp ../dist/macos/dmg_background.png "$TMP/.background/background.png"
|
||||
#cp ../dist/macos/DS_Store.in "$TMP/.DS_Store"
|
||||
#chmod go-rwx "$TMP/.DS_Store"
|
||||
ln -s /Applications "$TMP/Applications"
|
||||
# copies the prepared bundle into the dir that will become the DMG
|
||||
cp -R "$IN" "$TMP"
|
||||
|
||||
# create
|
||||
hdiutil makehybrid -hfs -hfs-volume-name "$NAME" -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg
|
||||
hdiutil convert -format UDZO -imagekey zlib-level=9 tmp.dmg -o "$OUT"
|
||||
|
||||
#genisoimage -D -V "Strawberry" -no-pad -r -apple -o $NAME.iso $TMP
|
||||
#dmg dmg $NAME.iso $OUT
|
||||
|
||||
# cleanup
|
||||
#rm tmp.dmg
|
||||
489
dist/macos/macdeploy.py
vendored
Executable file
@@ -0,0 +1,489 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Strawberry Music Player
|
||||
# This file was part of Clementine.
|
||||
#
|
||||
# Strawberry is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Strawberry 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from distutils import spawn
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import commands
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
LOGGER = logging.getLogger('macdeploy')
|
||||
|
||||
LIBRARY_SEARCH_PATH = ['/usr/local/lib']
|
||||
|
||||
FRAMEWORK_SEARCH_PATH = [
|
||||
'/Library/Frameworks',
|
||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||
]
|
||||
|
||||
QT_PLUGINS = [
|
||||
'platforms/libqcocoa.dylib',
|
||||
'sqldrivers/libqsqlite.dylib',
|
||||
'imageformats/libqgif.dylib',
|
||||
'imageformats/libqicns.dylib',
|
||||
'imageformats/libqico.dylib',
|
||||
'imageformats/libqjpeg.dylib',
|
||||
'imageformats/libqsvg.dylib',
|
||||
'imageformats/libqtiff.dylib',
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH = [
|
||||
'/usr/local/opt/qt/plugins',
|
||||
]
|
||||
|
||||
GSTREAMER_SEARCH_PATH = [
|
||||
'/usr/local/lib/gstreamer-1.0',
|
||||
]
|
||||
|
||||
GSTREAMER_PLUGINS = [
|
||||
|
||||
'libgstapetag.so',
|
||||
'libgstapp.so',
|
||||
'libgstaudioconvert.so',
|
||||
'libgstaudiofx.so',
|
||||
'libgstaudiomixer.so',
|
||||
'libgstaudioparsers.so',
|
||||
'libgstaudiorate.so',
|
||||
'libgstaudioresample.so',
|
||||
'libgstaudiotestsrc.so',
|
||||
'libgstauparse.so',
|
||||
'libgstautodetect.so',
|
||||
'libgstcoreelements.so',
|
||||
'libgstcoretracers.so',
|
||||
'libgstcutter.so',
|
||||
'libgstdebug.so',
|
||||
'libgstequalizer.so',
|
||||
'libgstgio.so',
|
||||
'libgsticydemux.so',
|
||||
'libgstid3demux.so',
|
||||
'libgstlevel.so',
|
||||
'libgstosxaudio.so',
|
||||
'libgstplayback.so',
|
||||
'libgstrawparse.so',
|
||||
'libgstrealmedia.so',
|
||||
'libgstreplaygain.so',
|
||||
'libgstsoup.so',
|
||||
'libgstspectrum.so',
|
||||
'libgsttypefindfunctions.so',
|
||||
'libgstvolume.so',
|
||||
'libgstxingmux.so',
|
||||
|
||||
'libgstflac.so',
|
||||
'libgstwavparse.so',
|
||||
'libgstfaac.so',
|
||||
'libgstfaad.so',
|
||||
'libgstlame.so',
|
||||
'libgstmad.so',
|
||||
'libgstogg.so',
|
||||
'libgstopus.so',
|
||||
'libgstasf.so',
|
||||
'libgstspeex.so',
|
||||
'libgsttaglib.so',
|
||||
'libgstvorbis.so',
|
||||
'libgstisomp4.so',
|
||||
|
||||
]
|
||||
|
||||
GIO_MODULES_SEARCH_PATH = ['/usr/local/lib/gio/modules',]
|
||||
|
||||
INSTALL_NAME_TOOL_APPLE = 'install_name_tool'
|
||||
INSTALL_NAME_TOOL_CROSS = 'x86_64-apple-darwin-%s' % INSTALL_NAME_TOOL_APPLE
|
||||
INSTALL_NAME_TOOL = INSTALL_NAME_TOOL_CROSS if spawn.find_executable(
|
||||
INSTALL_NAME_TOOL_CROSS) else INSTALL_NAME_TOOL_APPLE
|
||||
|
||||
OTOOL_APPLE = 'otool'
|
||||
OTOOL_CROSS = 'x86_64-apple-darwin-%s' % OTOOL_APPLE
|
||||
OTOOL = OTOOL_CROSS if spawn.find_executable(OTOOL_CROSS) else OTOOL_APPLE
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CouldNotFindFrameworkError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindGioModuleError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindQtPluginError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotParseFrameworkNameError(Error):
|
||||
pass
|
||||
|
||||
class InstallNameToolError(Error):
|
||||
pass
|
||||
|
||||
|
||||
class CouldNotFindGstreamerPluginError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindXinePluginError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindVLCPluginError(Error):
|
||||
pass
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print 'Usage: %s <bundle.app>' % sys.argv[0]
|
||||
|
||||
bundle_dir = sys.argv[1]
|
||||
|
||||
bundle_name = os.path.basename(bundle_dir).split('.')[0]
|
||||
|
||||
commands = []
|
||||
|
||||
frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
|
||||
commands.append(['mkdir', '-p', frameworks_dir])
|
||||
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
|
||||
commands.append(['mkdir', '-p', resources_dir])
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
||||
binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name)
|
||||
|
||||
fixed_libraries = set()
|
||||
fixed_frameworks = set()
|
||||
|
||||
|
||||
def GetBrokenLibraries(binary):
|
||||
#print "Checking libs for binary: %s" % binary
|
||||
output = subprocess.Popen([OTOOL, '-L', binary], stdout=subprocess.PIPE).communicate()[0]
|
||||
broken_libs = {'frameworks': [], 'libs': []}
|
||||
for line in [x.split(' ')[0].lstrip() for x in output.split('\n')[1:]]:
|
||||
#print "Checking line: %s" % line
|
||||
if not line: # skip empty lines
|
||||
continue
|
||||
if os.path.basename(binary) == os.path.basename(line):
|
||||
#print "mnope %s-%s" % (os.path.basename(binary), os.path.basename(line))
|
||||
continue
|
||||
if re.match(r'^\s*/System/', line):
|
||||
continue # System framework
|
||||
elif re.match(r'^\s*/usr/lib/', line):
|
||||
#print "unix style system lib"
|
||||
continue # unix style system library
|
||||
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
|
||||
# Potentially already fixed library
|
||||
relative_path = os.path.join(*line.split('/')[3:])
|
||||
if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
|
||||
broken_libs['frameworks'].append(relative_path)
|
||||
elif re.search(r'\w+\.framework', line):
|
||||
broken_libs['frameworks'].append(line)
|
||||
else:
|
||||
broken_libs['libs'].append(line)
|
||||
|
||||
return broken_libs
|
||||
|
||||
|
||||
def FindFramework(path):
|
||||
for search_path in FRAMEWORK_SEARCH_PATH:
|
||||
abs_path = os.path.join(search_path, path)
|
||||
if os.path.exists(abs_path):
|
||||
LOGGER.debug("Found framework '%s' in '%s'", path, search_path)
|
||||
return abs_path
|
||||
|
||||
raise CouldNotFindFrameworkError(path)
|
||||
|
||||
|
||||
def FindLibrary(path):
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
for search_path in LIBRARY_SEARCH_PATH:
|
||||
abs_path = os.path.join(search_path, path)
|
||||
if os.path.exists(abs_path):
|
||||
LOGGER.debug("Found library '%s' in '%s'", path, search_path)
|
||||
return abs_path
|
||||
else: # try harder---look for lib name in library folders
|
||||
newpath = os.path.join(search_path,os.path.basename(path))
|
||||
if os.path.exists(newpath):
|
||||
return newpath
|
||||
|
||||
raise CouldNotFindFrameworkError(path)
|
||||
|
||||
|
||||
def FixAllLibraries(broken_libs):
|
||||
for framework in broken_libs['frameworks']:
|
||||
FixFramework(framework)
|
||||
for lib in broken_libs['libs']:
|
||||
FixLibrary(lib)
|
||||
|
||||
|
||||
def FixFramework(path):
|
||||
if path in fixed_frameworks:
|
||||
return
|
||||
else:
|
||||
fixed_frameworks.add(path)
|
||||
abs_path = FindFramework(path)
|
||||
broken_libs = GetBrokenLibraries(abs_path)
|
||||
FixAllLibraries(broken_libs)
|
||||
|
||||
new_path = CopyFramework(abs_path)
|
||||
id = os.sep.join(new_path.split(os.sep)[3:])
|
||||
FixFrameworkId(new_path, id)
|
||||
for framework in broken_libs['frameworks']:
|
||||
FixFrameworkInstallPath(framework, new_path)
|
||||
for library in broken_libs['libs']:
|
||||
FixLibraryInstallPath(library, new_path)
|
||||
|
||||
|
||||
def FixLibrary(path):
|
||||
if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None:
|
||||
return
|
||||
else:
|
||||
fixed_libraries.add(path)
|
||||
abs_path = FindLibrary(path)
|
||||
if abs_path == "":
|
||||
print "Could not resolve %s, not fixing!" % path
|
||||
return
|
||||
broken_libs = GetBrokenLibraries(abs_path)
|
||||
FixAllLibraries(broken_libs)
|
||||
|
||||
new_path = CopyLibrary(abs_path)
|
||||
FixLibraryId(new_path)
|
||||
for framework in broken_libs['frameworks']:
|
||||
FixFrameworkInstallPath(framework, new_path)
|
||||
for library in broken_libs['libs']:
|
||||
FixLibraryInstallPath(library, new_path)
|
||||
|
||||
|
||||
def FixPlugin(abs_path, subdir):
|
||||
broken_libs = GetBrokenLibraries(abs_path)
|
||||
FixAllLibraries(broken_libs)
|
||||
|
||||
new_path = CopyPlugin(abs_path, subdir)
|
||||
for framework in broken_libs['frameworks']:
|
||||
FixFrameworkInstallPath(framework, new_path)
|
||||
for library in broken_libs['libs']:
|
||||
FixLibraryInstallPath(library, new_path)
|
||||
|
||||
|
||||
def FixBinary(path):
|
||||
broken_libs = GetBrokenLibraries(path)
|
||||
FixAllLibraries(broken_libs)
|
||||
for framework in broken_libs['frameworks']:
|
||||
FixFrameworkInstallPath(framework, path)
|
||||
for library in broken_libs['libs']:
|
||||
FixLibraryInstallPath(library, path)
|
||||
|
||||
|
||||
def CopyLibrary(path):
|
||||
new_path = os.path.join(frameworks_dir, os.path.basename(path))
|
||||
#args = ['cp', path, new_path]
|
||||
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
|
||||
LOGGER.info("Copying library '%s'", path)
|
||||
commands.append(args)
|
||||
args = ['chmod', 'u+w', new_path]
|
||||
commands.append(args)
|
||||
return new_path
|
||||
|
||||
|
||||
def CopyPlugin(path, subdir):
|
||||
new_path = os.path.join(plugins_dir, subdir, os.path.basename(path))
|
||||
args = ['mkdir', '-p', os.path.dirname(new_path)]
|
||||
commands.append(args)
|
||||
#args = ['cp', path, new_path]
|
||||
args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path]
|
||||
commands.append(args)
|
||||
LOGGER.info("Copying plugin '%s'", path)
|
||||
args = ['chmod', 'u+w', new_path]
|
||||
commands.append(args)
|
||||
return new_path
|
||||
|
||||
def CopyFramework(path):
|
||||
parts = path.split(os.sep)
|
||||
for i, part in enumerate(parts):
|
||||
if re.match(r'\w+\.framework', part):
|
||||
full_path = os.path.join(frameworks_dir, *parts[i:-1])
|
||||
framework_name = part.split(".framework")[0]
|
||||
break
|
||||
|
||||
def CopyFramework(src_binary):
|
||||
while os.path.islink(src_binary):
|
||||
src_binary = os.path.realpath(src_binary)
|
||||
|
||||
m = re.match(r'(.*/([^/]+)\.framework)/Versions/([^/]+)/.*', src_binary)
|
||||
if not m:
|
||||
raise CouldNotParseFrameworkNameError(src_binary)
|
||||
|
||||
src_base = m.group(1)
|
||||
name = m.group(2)
|
||||
version = m.group(3)
|
||||
|
||||
LOGGER.info('Copying framework %s version %s', name, version)
|
||||
|
||||
dest_base = os.path.join(frameworks_dir, '%s.framework' % name)
|
||||
dest_dir = os.path.join(dest_base, 'Versions', version)
|
||||
dest_binary = os.path.join(dest_dir, name)
|
||||
|
||||
commands.append(['mkdir', '-p', dest_dir])
|
||||
commands.append(['cp', src_binary, dest_binary])
|
||||
|
||||
# Copy special files from various places:
|
||||
# QtCore has Resources/qt_menu.nib (copy to app's Resources)
|
||||
# Sparkle has Resources/*
|
||||
# Qt* have Resources/Info.plist
|
||||
resources_src = os.path.join(src_base, 'Resources')
|
||||
menu_nib = os.path.join(resources_src, 'qt_menu.nib')
|
||||
if os.path.exists(menu_nib):
|
||||
LOGGER.info("Copying qt_menu.nib '%s'", menu_nib)
|
||||
commands.append(['cp', '-r', menu_nib, resources_dir])
|
||||
elif os.path.exists(resources_src):
|
||||
LOGGER.info("Copying resources dir '%s'", resources_src)
|
||||
commands.append(['cp', '-r', resources_src, dest_dir])
|
||||
|
||||
info_plist = os.path.join(src_base, 'Contents', 'Info.plist')
|
||||
if os.path.exists(info_plist):
|
||||
LOGGER.info("Copying special file '%s'", info_plist)
|
||||
resources_dest = os.path.join(dest_dir, 'Resources')
|
||||
commands.append(['mkdir', resources_dest])
|
||||
commands.append(['cp', '-r', info_plist, resources_dest])
|
||||
|
||||
# Create symlinks in the Framework to make it look like
|
||||
# https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
|
||||
commands.append([
|
||||
'ln', '-sf', 'Versions/Current/%s' % name, os.path.join(dest_base, name)
|
||||
])
|
||||
commands.append([
|
||||
'ln', '-sf', 'Versions/Current/Resources',
|
||||
os.path.join(dest_base, 'Resources')
|
||||
])
|
||||
commands.append(
|
||||
['ln', '-sf', version, os.path.join(dest_base, 'Versions/Current')])
|
||||
|
||||
return dest_binary
|
||||
|
||||
|
||||
def FixId(path, library_name):
|
||||
id = '@executable_path/../Frameworks/%s' % library_name
|
||||
args = [INSTALL_NAME_TOOL, '-id', id, path]
|
||||
commands.append(args)
|
||||
|
||||
|
||||
def FixLibraryId(path):
|
||||
library_name = os.path.basename(path)
|
||||
FixId(path, library_name)
|
||||
|
||||
|
||||
def FixFrameworkId(path, id):
|
||||
FixId(path, id)
|
||||
|
||||
|
||||
def FixInstallPath(library_path, library, new_path):
|
||||
args = [INSTALL_NAME_TOOL, '-change', library_path, new_path, library]
|
||||
commands.append(args)
|
||||
|
||||
|
||||
def FindSystemLibrary(library_name):
|
||||
for path in ['/lib', '/usr/lib']:
|
||||
full_path = os.path.join(path, library_name)
|
||||
if os.path.exists(full_path):
|
||||
return full_path
|
||||
return None
|
||||
|
||||
|
||||
def FixLibraryInstallPath(library_path, library):
|
||||
system_library = FindSystemLibrary(os.path.basename(library_path))
|
||||
if system_library is None:
|
||||
new_path = '@executable_path/../Frameworks/%s' % os.path.basename(library_path)
|
||||
FixInstallPath(library_path, library, new_path)
|
||||
else:
|
||||
FixInstallPath(library_path, library, system_library)
|
||||
|
||||
|
||||
def FixFrameworkInstallPath(library_path, library):
|
||||
parts = library_path.split(os.sep)
|
||||
for i, part in enumerate(parts):
|
||||
if re.match(r'\w+\.framework', part):
|
||||
full_path = os.path.join(*parts[i:])
|
||||
break
|
||||
new_path = '@executable_path/../Frameworks/%s' % full_path
|
||||
FixInstallPath(library_path, library, new_path)
|
||||
|
||||
|
||||
def FindXinePlugin(name):
|
||||
for path in XINEPLUGIN_SEARCH_PATH:
|
||||
if os.path.exists(path):
|
||||
for dir, dirs, files in os.walk(path):
|
||||
if name in files:
|
||||
return os.path.join(dir, name)
|
||||
raise CouldNotFindXinePluginError(name)
|
||||
|
||||
|
||||
def FindQtPlugin(name):
|
||||
for path in QT_PLUGINS_SEARCH_PATH:
|
||||
if os.path.exists(path):
|
||||
if os.path.exists(os.path.join(path, name)):
|
||||
return os.path.join(path, name)
|
||||
raise CouldNotFindQtPluginError(name)
|
||||
|
||||
|
||||
def FindGstreamerPlugin(name):
|
||||
for path in GSTREAMER_SEARCH_PATH:
|
||||
if os.path.exists(path):
|
||||
for dir, dirs, files in os.walk(path):
|
||||
if name in files:
|
||||
return os.path.join(dir, name)
|
||||
raise CouldNotFindGstreamerPluginError(name)
|
||||
|
||||
|
||||
def FindGioModule(name):
|
||||
for path in GIO_MODULES_SEARCH_PATH:
|
||||
if os.path.exists(path):
|
||||
for dir, dirs, files in os.walk(path):
|
||||
if name in files:
|
||||
return os.path.join(dir, name)
|
||||
raise CouldNotFindGioModuleError(name)
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(filename='macdeploy.log', level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s')
|
||||
|
||||
FixBinary(binary)
|
||||
|
||||
for plugin in GSTREAMER_PLUGINS:
|
||||
FixPlugin(FindGstreamerPlugin(plugin), 'gstreamer')
|
||||
|
||||
#FixPlugin(FindGstreamerPlugin('gst-plugin-scanner'), '.')
|
||||
FixPlugin(FindGioModule('libgiognutls.so'), 'gio-modules')
|
||||
FixPlugin(FindGioModule('libgiognomeproxy.so'), 'gio-modules')
|
||||
|
||||
try:
|
||||
FixPlugin('strawberry-tagreader', '.')
|
||||
except:
|
||||
print 'Failed to find blob: %s' % traceback.format_exc()
|
||||
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
||||
if len(sys.argv) <= 2:
|
||||
print 'Would run %d commands:' % len(commands)
|
||||
for command in commands:
|
||||
print ' '.join(command)
|
||||
|
||||
print 'OK?'
|
||||
raw_input()
|
||||
|
||||
for command in commands:
|
||||
p = subprocess.Popen(command)
|
||||
os.waitpid(p.pid, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
dist/macos/strawberry.icns
vendored
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
@@ -9,7 +9,7 @@ URL: http://www.strawbs.org/
|
||||
Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
|
||||
BuildRequires: boost-devel
|
||||
BuildRequires: libboost_headers-devel
|
||||
BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: gcc-c++
|
||||
@@ -17,8 +17,16 @@ BuildRequires: hicolor-icon-theme
|
||||
BuildRequires: libQt5Gui-private-headers-devel
|
||||
BuildRequires: liblastfm-qt5-devel
|
||||
BuildRequires: make
|
||||
BuildRequires: git
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: update-desktop-files
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(gio-2.0)
|
||||
BuildRequires: pkgconfig(gio-unix-2.0)
|
||||
BuildRequires: pkgconfig(gthread-2.0)
|
||||
BuildRequires: pkgconfig(dbus-1)
|
||||
BuildRequires: pkgconfig(alsa)
|
||||
BuildRequires: pkgconfig(protobuf)
|
||||
BuildRequires: pkgconfig(Qt5Concurrent)
|
||||
BuildRequires: pkgconfig(Qt5Core)
|
||||
BuildRequires: pkgconfig(Qt5Gui)
|
||||
@@ -30,17 +38,11 @@ BuildRequires: pkgconfig(Qt5WebKit)
|
||||
BuildRequires: pkgconfig(Qt5WebKitWidgets)
|
||||
BuildRequires: pkgconfig(Qt5Widgets)
|
||||
BuildRequires: pkgconfig(Qt5X11Extras)
|
||||
BuildRequires: pkgconfig(alsa)
|
||||
BuildRequires: pkgconfig(gio-2.0)
|
||||
BuildRequires: pkgconfig(gio-unix-2.0)
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(glu)
|
||||
BuildRequires: pkgconfig(gstreamer-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-app-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-audio-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-base-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-tag-1.0)
|
||||
BuildRequires: pkgconfig(gthread-2.0)
|
||||
BuildRequires: pkgconfig(libcdio)
|
||||
BuildRequires: pkgconfig(libchromaprint)
|
||||
BuildRequires: pkgconfig(libgpod-1.0)
|
||||
@@ -48,13 +50,11 @@ BuildRequires: pkgconfig(libmtp)
|
||||
BuildRequires: pkgconfig(libnotify)
|
||||
BuildRequires: pkgconfig(libpulse)
|
||||
BuildRequires: pkgconfig(libudf)
|
||||
BuildRequires: pkgconfig(libxml-2.0)
|
||||
BuildRequires: pkgconfig(sqlite3) >= 3.7
|
||||
BuildRequires: pkgconfig(taglib) >= 1.11
|
||||
BuildRequires: pkgconfig(libxine)
|
||||
BuildRequires: pkgconfig(libvlc)
|
||||
BuildRequires: pkgconfig(libxml-2.0)
|
||||
BuildRequires: pkgconfig(protobuf)
|
||||
BuildRequires: pkgconfig(sqlite3) >= 3.7
|
||||
BuildRequires: pkgconfig(taglib) >= 1.8
|
||||
Requires: libtag1 >= 1.8
|
||||
|
||||
%description
|
||||
Strawberry is a audio player and music collection organizer.
|
||||
@@ -62,12 +62,12 @@ It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
|
||||
Features:
|
||||
* Play and organize music
|
||||
* Edit tags on music files
|
||||
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
|
||||
* Native desktop notifications
|
||||
* Playlists in multiple formats
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Edit tags on music files
|
||||
* Fetch tags from MusicBrainz
|
||||
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Support for multiple backends
|
||||
|
||||
%prep
|
||||
114
dist/scripts/gen-icons-resource.sh
vendored
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/sh
|
||||
|
||||
sizes="128x128 64x64 48x48 32x32 22x22"
|
||||
|
||||
#
|
||||
|
||||
for i in full/*
|
||||
do
|
||||
source=$i
|
||||
file=`basename $i`
|
||||
|
||||
id=`identify "$i"` || exit 1
|
||||
if [ "$id" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine format and geometry for image: \"$i\"."
|
||||
continue
|
||||
fi
|
||||
g=`echo $id | awk '{print $3}'` || exit 1
|
||||
if [ "$g" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine geometry for image: \"$i\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
if [ "$w" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine width for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
if [ "$h" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine height for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
for x in $sizes
|
||||
do
|
||||
|
||||
dest="$x/$file"
|
||||
if [ -f $dest ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
x_w=$(echo $x | cut -d 'x' -f1)
|
||||
x_h=$(echo $x | cut -d 'x' -f2)
|
||||
|
||||
if [ "$w" -lt "$x_w" ] || [ "$h" -lt "$x_h" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "convert -verbose -resize $x $source $dest"
|
||||
convert -verbose -resize $x $source $dest
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
for i in $sizes
|
||||
do
|
||||
for x in $i/*
|
||||
do
|
||||
file=`basename $x`
|
||||
if ! [ -f "full/$file" ]; then
|
||||
echo "Warning: full/$file does not exist, but $x exists."
|
||||
fi
|
||||
|
||||
id=`identify "$x"` || exit 1
|
||||
if [ "$id" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine format and geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
g=`echo $id | awk '{print $3}'` || exit 1
|
||||
if [ "$g" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine geometry for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
# Geometry can be 563x144+0+0 or 75x98
|
||||
# we need to get rid of the plus (+) and the x characters:
|
||||
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
|
||||
if [ "$w" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine width for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
h=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $2}'` || exit 1
|
||||
if [ "$h" = "" ] ; then
|
||||
echo "ERROR: Cannot dermine height for image: \"$x\"."
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! [ "${h}x${w}" = "$i" ]; then
|
||||
echo "Warning: $x is not $i, but ${h}x${w}!"
|
||||
fi
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
file="../icons.qrc"
|
||||
rm -rf "$file"
|
||||
echo "<RCC>" >>$file
|
||||
echo "<qresource prefix=\"/\">" >>$file
|
||||
|
||||
for i in full $sizes
|
||||
do
|
||||
for x in $i/*
|
||||
do
|
||||
f=`basename $x`
|
||||
echo " <file>icons/$i/$f</file>" >>$file
|
||||
done
|
||||
done
|
||||
|
||||
echo "</qresource>" >>$file
|
||||
echo "</RCC>" >>$file
|
||||
|
||||
@@ -2,19 +2,26 @@
|
||||
|
||||
name=strawberry
|
||||
version="@STRAWBERRY_VERSION_PACKAGE@"
|
||||
root=$(cd "${0%/*}/.." && echo $PWD/${0##*/})
|
||||
gitrev="@INCLUDE_GIT_REVISION@"
|
||||
root=$(cd "${0%/*}/../.." && echo $PWD/${0##*/})
|
||||
root=`dirname "$root"`
|
||||
rootnoslash=`echo $root | sed "s/^\///"`
|
||||
|
||||
if ! [ "$gitrev" = "ON" ]; then
|
||||
exclude_vcs="--exclude-vcs"
|
||||
fi
|
||||
|
||||
echo "Creating $name-$version.tar.xz..."
|
||||
|
||||
rm -f "$name-$version.tar.xz"
|
||||
tar -cJf $name-$version.tar.xz \
|
||||
--transform "s,^$rootnoslash,$name-$version," \
|
||||
--exclude-vcs \
|
||||
--exclude "$root/dist/*.tar" \
|
||||
--exclude "$root/dist/*.tar.*" \
|
||||
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
||||
--exclude "*.tar" \
|
||||
--exclude "*.tar.*" \
|
||||
--exclude "*.bz" \
|
||||
--exclude "*.bz2" \
|
||||
--exclude "*.xz" \
|
||||
--exclude ".directory" \
|
||||
--exclude "$root/CMakeLists.txt.user" \
|
||||
--exclude "$root/build" \
|
||||
--exclude ".directory" \
|
||||
"$root"
|
||||
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
676
dist/windows/Capabilities.nsh
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
_____________________________________________________________________________
|
||||
|
||||
Application Capabilities (Default Programs)
|
||||
_____________________________________________________________________________
|
||||
|
||||
By Joel Spadin
|
||||
Loosely based on code taken from http://nsis.sourceforge.net/File_Association
|
||||
|
||||
These functions register an application with Windows Vista's and Windows 7's
|
||||
Default Programs window.
|
||||
|
||||
Usage:
|
||||
|
||||
!include "Capabilities.nsh"
|
||||
!define CAPABILITIES_NAME "[program name]"
|
||||
!define CAPABILITIES_DESCRIPTION "[description]"
|
||||
!define CAPABILITIES_PROGID "[progid]"
|
||||
!define CAPABILITIES_PATH "[path]"
|
||||
...
|
||||
|
||||
During install, call ${RegisterCapabilities}, then use the other register
|
||||
macros to create file type, MIME, and protocol associations.
|
||||
|
||||
During uninstall, call ${UnRegisterCapabilities}
|
||||
|
||||
_______________________________________________________________________________
|
||||
|
||||
More information about Default Programs and Client Types can be found here:
|
||||
http://msdn.microsoft.com/en-us/library/cc144154(VS.85).aspx
|
||||
http://msdn.microsoft.com/en-us/library/cc144109(v=VS.85).aspx
|
||||
|
||||
Defines: All defines not marked [optional] are required.
|
||||
|
||||
CAPABILITIES_NAME
|
||||
The canonical name of the program.
|
||||
|
||||
CAPABILITIES_LOCAL_NAME [optional]
|
||||
The localized name of the program as it appears in Default Programs.
|
||||
This should be in the format "@FilePath,-StringID" where FilePath is the
|
||||
path to a .dll or .exe file and StringID is the ID of a resource contained
|
||||
in the file.
|
||||
|
||||
CAPABILITIES_DESCRIPTION
|
||||
The localized description shown in Default Programs. This can be either a
|
||||
string or in the same format as CAPABILITIES_LOCAL_NAME
|
||||
|
||||
CAPABILITIES_PROGID
|
||||
An identifier used in file associations. Usually, this is the name of the
|
||||
program. This should not have any spaces in it.
|
||||
|
||||
CAPABILITIES_PATH
|
||||
The location where capabilities info is stored in the registry.
|
||||
The "Capabilities" key will automatically be added. If the application is
|
||||
a client of some sort, (browser, email, media player, etc.) use
|
||||
"Software\Clients\[ClientType]\[ProgramName]". Otherwise, use
|
||||
"Software\[CompanyName]\[ProgramName]" or just "Software\[ProgramName]".
|
||||
|
||||
CAPABILITIES_ICON [optional]
|
||||
The icon shown in Default Programs. This should be in the format
|
||||
"FilePath,IconIndex" where FilePath is the path to a file containing the
|
||||
icon. If IconIndex is positive, the number is used as the index of the
|
||||
zero-based array of icons stored in the file. If IconIndex is negative,
|
||||
the absolute value is used as a resource ID.
|
||||
|
||||
CAPABILITIES_REINSTALL [optional]
|
||||
The command executed when a user uses Set Program Access and Computer
|
||||
Defaults to select this application as the default for its client type.
|
||||
This command should launch a program that associates the application with
|
||||
all the file and protocol types it can handle.
|
||||
|
||||
CAPABILITIES_HIDE_ICONS [optional]
|
||||
The command executed when a user uses Set Program Access and Computer
|
||||
Defaults to disable access to this application. This command should launch
|
||||
a program that hides all shortcuts and access points to this application.
|
||||
It should also prevent the application from being run automatically and
|
||||
update the IconsVisible registry value to 0.
|
||||
|
||||
CAPABILITIES_SHOW_ICONS [optional]
|
||||
The command executed when a user uses Set Program Access and Computer
|
||||
Defaults to enable access to this application. This command should launch
|
||||
a program that restores shortcuts and access points to the application,
|
||||
allows the program to run, and updates the IconsVisible registry value to 1.
|
||||
|
||||
|
||||
Macros:
|
||||
|
||||
${RegisterCapabilities}
|
||||
Registers the program with Default Programs. Call this once on install
|
||||
before using any other functions.
|
||||
|
||||
${UnRegisterCapabilities}
|
||||
Un-registers the program and all its associations. Call this once on
|
||||
uninstall to clean up all installed registry values.
|
||||
|
||||
${RegisterFileType} "[extension]" "[executable]" "[icon]" "[description]"
|
||||
Registers a file type with the program
|
||||
extension: The file extension to register (ex: .txt)
|
||||
executable: The executable that opens the file type
|
||||
icon: The icon shown for the file type
|
||||
description: Description for the file type shown in Explorer
|
||||
|
||||
${RegisterMediaType} "[extension]" "[executable]" "[icon]" "[description]"
|
||||
Registers a media file type with the program (has a "Play" command)
|
||||
(arguments are same as RegisterFileType)
|
||||
|
||||
${RegisterMimeType} "[mime type]" "[shortname]" "[clsid]"
|
||||
Registers a mime type with the program
|
||||
mime type: The MIME type to register (ex: audio/mp3)
|
||||
shortname: A short identifier for the type (ex: mp3)
|
||||
clsid: The CLSID of the program to handle files of this type
|
||||
|
||||
${RegisterProtocol} "[protocol]" "[executable]" "[icon]" "[description]"
|
||||
Registers a URL protocol with the program
|
||||
protocol: The protocol to register (ex: http)
|
||||
(other arguments are same as RegisterFileType)
|
||||
|
||||
${UnRegisterFileType} "[extension]"
|
||||
Un-registers a previously registered file type
|
||||
extension: The file extension to un-register
|
||||
|
||||
${UnRegisterMimeType} "[mime type]"
|
||||
Un-registers a previously registered MEME type
|
||||
mime type: The MIME type to un-register
|
||||
|
||||
${UnRegisterProtocol} "[protocol]"
|
||||
Un-registers a previously registered URL protocol
|
||||
protocol: The URL protocol to un-register
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
!ifndef Capabilities_INCLUDED
|
||||
!define Capabilities_INCLUDED
|
||||
|
||||
!include "Util.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
|
||||
${StrCase}
|
||||
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!ifndef _Capabilities_VERBOSE
|
||||
!define _Capabilities_VERBOSE 3
|
||||
!endif
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
!define Capabilities_VERBOSE `!insertmacro Capabilities_VERBOSE`
|
||||
!verbose pop
|
||||
|
||||
!macro Capabilities_VERBOSE _VERBOSE
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!undef _Capabilities_VERBOSE
|
||||
!define _Capabilities_VERBOSE ${_VERBOSE}
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro RegisterCapabilitiesCall
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
${CallArtificialFunction} RegisterCapabilities_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterCapabilitiesCall
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
${CallArtificialFunction} UnRegisterCapabilities_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro RegisterFileTypeCall _EXTENSION _EXECUTABLE _ICON _DESCRIPTION
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_DESCRIPTION}`
|
||||
Push `${_ICON}`
|
||||
Push `${_EXECUTABLE}`
|
||||
Push `${_EXTENSION}`
|
||||
${CallArtificialFunction} RegisterFileType_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro RegisterMediaTypeCall _EXTENSION _EXECUTABLE _ICON _DESCRIPTION
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_DESCRIPTION}`
|
||||
Push `${_ICON}`
|
||||
Push `${_EXECUTABLE}`
|
||||
Push `${_EXTENSION}`
|
||||
${CallArtificialFunction} RegisterMediaType_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro RegisterMimeTypeCall _MIMETYPE _SHORTNAME _CLSID
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_CLSID}`
|
||||
Push `${_SHORTNAME}`
|
||||
Push `${_MIMETYPE}`
|
||||
${CallArtificialFunction} RegisterMimeType_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro RegisterProtocolCall _PROTOCOL _EXECUTABLE _ICON _DESCRIPTION
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_DESCRIPTION}`
|
||||
Push `${_ICON}`
|
||||
Push `${_EXECUTABLE}`
|
||||
Push `${_PROTOCOL}`
|
||||
${CallArtificialFunction} RegisterProtocol_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterFileTypeCall _EXTENSION
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_EXTENSION}`
|
||||
${CallArtificialFunction} UnRegisterFileType_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterMimeTypeCall _MIMETYPE
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_MIMETYPE}`
|
||||
${CallArtificialFunction} UnRegisterMimeType_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterProtocolCall _PROTOCOL
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push `${_MIMETYPE}`
|
||||
${CallArtificialFunction} UnRegisterProtocol_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
!define RegisterCapabilities `!insertmacro RegisterCapabilitiesCall`
|
||||
!define un.RegisterCapabilities `!insertmacro RegisterCapabilitiesCall`
|
||||
|
||||
!macro RegisterCapabilities
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterCapabilities
|
||||
!macroend
|
||||
|
||||
!macro RegisterCapabilities_
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
Push $0
|
||||
|
||||
!ifndef CAPABILITIES_PATH
|
||||
!error "CAPABILITIES_PATH not defined"
|
||||
!endif
|
||||
!ifndef CAPABILITIES_NAME
|
||||
!error "CAPABILITIES_NAME not defined"
|
||||
!endif
|
||||
!ifndef CAPABILITIES_PROGID
|
||||
!error "CAPABILITIES_PROGID not defined"
|
||||
!endif
|
||||
!ifndef CAPABILITIES_DESCRIPTION
|
||||
!error "CAPABILITIES_DESCRIPTION not defined"
|
||||
!endif
|
||||
|
||||
StrCpy $0 "${CAPABILITIES_PATH}\Capabilities"
|
||||
; add the application to RegisteredApplications
|
||||
WriteRegStr HKLM "Software\RegisteredApplications" "${CAPABILITIES_NAME}" "$0"
|
||||
|
||||
; write application info
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}" "" "${CAPABILITIES_NAME}"
|
||||
|
||||
!ifdef CAPABILITIES_LOCAL_NAME
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}" "LocalizedString" "${CAPABILITIES_LOCAL_NAME}"
|
||||
!endif
|
||||
!ifdef CAPABILITIES_ICON
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\DefaultIcon" "" "${CAPABILITIES_ICON}"
|
||||
!endif
|
||||
|
||||
; write installinfo if defined
|
||||
!ifdef CAPABILITIES_REINSTALL
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\InstallInfo" "ReinstallCommand" "${CAPABILITIES_REINSTALL}"
|
||||
!endif
|
||||
!ifdef CAPABILITIES_HIDE_ICONS
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\InstallInfo" "HideIconsCommand" "${CAPABILITIES_HIDE_ICONS}"
|
||||
WriteRegDWORD HKLM "${CAPABILITIES_PATH}\InstallInfo" "IconsVisible" 0x1
|
||||
!endif
|
||||
!ifdef CAPABILITIES_SHOW_ICONS
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\InstallInfo" "ShowIconsCommand" "${CAPABILITIES_SHOW_ICONS}"
|
||||
WriteRegDWORD HKLM "${CAPABILITIES_PATH}\InstallInfo" "IconsVisible" 0x1
|
||||
!endif
|
||||
|
||||
; write application capabilities info
|
||||
!ifdef CAPABILITIES_LOCAL_NAME
|
||||
WriteRegStr HKLM "$0" "ApplicationName" "${CAPABILITIES_LOCAL_NAME}"
|
||||
!else
|
||||
WriteRegStr HKLM "$0" "ApplicationName" "${CAPABILITIES_NAME}"
|
||||
!endif
|
||||
WriteRegStr HKLM "$0" "ApplicationDescription" "${CAPABILITIES_DESCRIPTION}"
|
||||
|
||||
Pop $0
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define UnRegisterCapabilities `!insertmacro UnRegisterCapabilitiesCall`
|
||||
!define un.UnRegisterCapabilities `!insertmacro UnRegisterCapabilitiesCall`
|
||||
|
||||
!macro UnRegisterCapabilities
|
||||
!macroend
|
||||
|
||||
!macro un.UnRegisterCapabilities
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterCapabilities_
|
||||
!define MacroID ${__LINE__}
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Push $0
|
||||
Push $1
|
||||
|
||||
; remove all file associations
|
||||
FileTypeLoop_${MacroID}:
|
||||
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" 0
|
||||
StrCmp $0 "" FileTypeDone_${MacroID}
|
||||
|
||||
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$0"
|
||||
DeleteRegKey HKCR $1
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$0"
|
||||
|
||||
Goto FileTypeLoop_${MacroID}
|
||||
FileTypeDone_${MacroID}:
|
||||
|
||||
; remove all MIME associations
|
||||
MimeTypeLoop_${MacroID}:
|
||||
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" 0
|
||||
StrCmp $0 "" MimeTypeDone_${MacroID}
|
||||
|
||||
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$0"
|
||||
DeleteRegKey HKCR "$1"
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$0"
|
||||
|
||||
Goto MimeTypeLoop_${MacroID}
|
||||
MimeTypeDone_${MacroID}:
|
||||
|
||||
; remove all protocol associations
|
||||
ProtocolLoop_${MacroID}:
|
||||
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" 0
|
||||
StrCmp $0 "" ProtocolDone_${MacroID}
|
||||
|
||||
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$0"
|
||||
DeleteRegKey HKCR "$1"
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$0"
|
||||
|
||||
Goto ProtocolLoop_${MacroID}
|
||||
ProtocolDone_${MacroID}:
|
||||
|
||||
|
||||
; remove capabilities keys
|
||||
DeleteRegValue HKLM "Software\RegisteredApplications" "${CAPABILITIES_NAME}"
|
||||
DeleteRegKey HKLM ${CAPABILITIES_PATH}
|
||||
|
||||
Pop $1
|
||||
Pop $0
|
||||
!verbose pop
|
||||
!undef MacroID
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
!define RegisterFileType `!insertmacro RegisterFileTypeCall`
|
||||
!define un.RegisterFileType `!insertmacro RegisterFileTypeCall`
|
||||
|
||||
!macro RegisterFileType
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterFileType
|
||||
!macroend
|
||||
|
||||
|
||||
!macro RegisterFileType_
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R3 ;ext
|
||||
Exch
|
||||
Exch $R2 ;exe
|
||||
Exch 2
|
||||
Exch $R1 ;icon
|
||||
Exch
|
||||
Exch 3
|
||||
Exch $R0 ;desc
|
||||
Push $0
|
||||
|
||||
; create an association name
|
||||
; ex: .mp3 becomes ProgID.AssocFile.MP3
|
||||
${StrCase} $0 "$R3" "U"
|
||||
StrCpy $0 "${CAPABILITIES_PROGID}.AssocFile$0"
|
||||
|
||||
; link capabilities to association in classes root
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R3" "$0"
|
||||
|
||||
; write file association in classes root
|
||||
WriteRegStr HKCR "$0" "" "$R0"
|
||||
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
|
||||
WriteRegStr HKCR "$0\shell" "" "Open"
|
||||
WriteRegStr HKCR "$0\shell\open" "" "&Open"
|
||||
WriteRegStr HKCR "$0\shell\open\command" "" '"$R2" "%1"'
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
Pop $R1
|
||||
Pop $R2
|
||||
Pop $R3
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
!define RegisterMediaType `!insertmacro RegisterMediaTypeCall`
|
||||
!define un.RegisterMediaType `!insertmacro RegisterMediaTypeCall`
|
||||
|
||||
!macro RegisterMediaType
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterMediaType
|
||||
!macroend
|
||||
|
||||
|
||||
!macro RegisterMediaType_
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R3 ;ext
|
||||
Exch
|
||||
Exch $R2 ;exe
|
||||
Exch 2
|
||||
Exch $R1 ;icon
|
||||
Exch
|
||||
Exch 3
|
||||
Exch $R0 ;desc
|
||||
Push $0
|
||||
|
||||
|
||||
; create an association name
|
||||
; ex: .mp3 becomes ProgID.AssocFile.MP3
|
||||
${StrCase} $0 "$R3" "U"
|
||||
StrCpy $0 "${CAPABILITIES_PROGID}.AssocFile$0"
|
||||
|
||||
; link capabilities to association in classes root
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R3" "$0"
|
||||
|
||||
; write file association in classes root
|
||||
WriteRegStr HKCR "$0" "" "$R0"
|
||||
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
|
||||
WriteRegStr HKCR "$0\shell" "" "Play"
|
||||
WriteRegStr HKCR "$0\shell\open" "" "&Open"
|
||||
WriteRegStr HKCR "$0\shell\open\command" "" '"$R2" "%1"'
|
||||
WriteRegStr HKCR "$0\shell\play" "" "&Play"
|
||||
WriteRegStr HKCR "$0\shell\play\command" "" '"$R2" "%L"'
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
Pop $R1
|
||||
Pop $R2
|
||||
Pop $R3
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
!define RegisterMimeType `!insertmacro RegisterMimeTypeCall`
|
||||
!define un.RegisterMimeType `!insertmacro RegisterMimeTypeCall`
|
||||
|
||||
!macro RegisterMimeType
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterMimeType
|
||||
!macroend
|
||||
|
||||
|
||||
!macro RegisterMimeType_
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R2 ;mime
|
||||
Exch
|
||||
Exch $R1 ;shortname
|
||||
Exch
|
||||
Exch 2
|
||||
Exch $R0 ;clsid
|
||||
|
||||
Push $0
|
||||
|
||||
; create an association name
|
||||
; ex: audio/mp3 becomes ProgID.AssocMIME.MP3
|
||||
${StrCase} $0 "$R1" "U"
|
||||
StrCpy $0 "${CAPABILITIES_PROGID}.AssocMIME.$0"
|
||||
|
||||
; link capabilities to association in classes root
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R2" "$0"
|
||||
|
||||
; write file association in classes root
|
||||
WriteRegStr HKCR "$0\CLSID" "" "$R0"
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
Pop $R1
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define RegisterProtocol `!insertmacro RegisterProtocolCall`
|
||||
!define un.RegisterProtocol `!insertmacro RegisterProtocolCall`
|
||||
|
||||
!macro RegisterProtocol
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterProtocol
|
||||
!macroend
|
||||
|
||||
|
||||
!macro RegisterProtocol_
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R3 ;protocol
|
||||
Exch
|
||||
Exch $R2 ;exe
|
||||
Exch 2
|
||||
Exch $R1 ;icon
|
||||
Exch
|
||||
Exch 3
|
||||
Exch $R0 ;desc
|
||||
Push $0
|
||||
|
||||
|
||||
; create an association name
|
||||
; ex: http becomes ProgID.AssocProtocol.HTTP
|
||||
${StrCase} $0 "$R3" "U"
|
||||
StrCpy $0 "${CAPABILITIES_PROGID}.AssocProtocol.$0"
|
||||
|
||||
; link capabilities to association in classes root
|
||||
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R3" "$0"
|
||||
|
||||
; write file association in classes root
|
||||
WriteRegStr HKCR "$0" "" "$R0"
|
||||
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
|
||||
WriteRegStr HKCR "$0\shell\open" "" "&Open"
|
||||
WriteRegStr HKCR "$0\shell\open\command" "" '"$R2" "%1"'
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
Pop $R1
|
||||
Pop $R2
|
||||
Pop $R3
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
!define UnRegisterFileType `!insertmacro UnRegisterFileTypeCall`
|
||||
!define un.UnRegisterFileType `!insertmacro UnRegisterFileTypeCall`
|
||||
|
||||
!macro UnRegisterFileType
|
||||
!macroend
|
||||
|
||||
!macro un.UnRegisterFileType
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterFileType_
|
||||
!define MacroID ${__LINE__}
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R0 ;ext
|
||||
Push $0
|
||||
|
||||
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R0"
|
||||
StrCmp $0 "" skip_${MacroID}
|
||||
|
||||
DeleteRegKey HKCR "$0"
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R0"
|
||||
skip_${MacroID}:
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
!verbose pop
|
||||
!undef MacroID
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define UnRegisterMimeType `!insertmacro UnRegisterMimeTypeCall`
|
||||
!define un.UnRegisterMimeType `!insertmacro UnRegisterMimeTypeCall`
|
||||
|
||||
!macro UnRegisterMimeType
|
||||
!macroend
|
||||
|
||||
!macro un.UnRegisterMimeType
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterMimeType_
|
||||
!define MacroID ${__LINE__}
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R0 ;mime
|
||||
Push $0
|
||||
|
||||
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R0"
|
||||
StrCmp $0 "" skip_${MacroID}
|
||||
|
||||
DeleteRegKey HKCR "$0"
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R0"
|
||||
skip_${MacroID}:
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
!verbose pop
|
||||
!undef MacroID
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define UnRegisterProtocol `!insertmacro UnRegisterProtocolCall`
|
||||
!define un.UnRegisterProtocol `!insertmacro UnRegisterProtocolCall`
|
||||
|
||||
!macro UnRegisterProtocol
|
||||
!macroend
|
||||
|
||||
!macro un.UnRegisterProtocol
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterProtocol_
|
||||
!define MacroID ${__LINE__}
|
||||
!verbose push
|
||||
!verbose ${_Capabilities_VERBOSE}
|
||||
|
||||
Exch $R0 ;protocol
|
||||
Push $0
|
||||
|
||||
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R0"
|
||||
StrCmp $0 "" skip_${MacroID}
|
||||
|
||||
DeleteRegKey HKCR "$0"
|
||||
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R0"
|
||||
skip_${MacroID}:
|
||||
|
||||
Pop $0
|
||||
Pop $R0
|
||||
!verbose pop
|
||||
!undef MacroID
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
|
||||
!endif
|
||||
190
dist/windows/FileAssociation.nsh
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
_____________________________________________________________________________
|
||||
|
||||
File Association
|
||||
_____________________________________________________________________________
|
||||
|
||||
Based on code taken from http://nsis.sourceforge.net/File_Association
|
||||
|
||||
Usage in script:
|
||||
1. !include "FileAssociation.nsh"
|
||||
2. [Section|Function]
|
||||
${FileAssociationFunction} "Param1" "Param2" "..." $var
|
||||
[SectionEnd|FunctionEnd]
|
||||
|
||||
FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
|
||||
|
||||
_____________________________________________________________________________
|
||||
|
||||
${RegisterExtension} "[executable]" "[extension]" "[description]"
|
||||
|
||||
"[executable]" ; executable which opens the file format
|
||||
;
|
||||
"[extension]" ; extension, which represents the file format to open
|
||||
;
|
||||
"[description]" ; description for the extension. This will be display in Windows Explorer.
|
||||
;
|
||||
|
||||
|
||||
${UnRegisterExtension} "[extension]" "[description]"
|
||||
|
||||
"[extension]" ; extension, which represents the file format to open
|
||||
;
|
||||
"[description]" ; description for the extension. This will be display in Windows Explorer.
|
||||
;
|
||||
|
||||
_____________________________________________________________________________
|
||||
|
||||
Macros
|
||||
_____________________________________________________________________________
|
||||
|
||||
Change log window verbosity (default: 3=no script)
|
||||
|
||||
Example:
|
||||
!include "FileAssociation.nsh"
|
||||
!insertmacro RegisterExtension
|
||||
${FileAssociation_VERBOSE} 4 # all verbosity
|
||||
!insertmacro UnRegisterExtension
|
||||
${FileAssociation_VERBOSE} 3 # no script
|
||||
*/
|
||||
|
||||
|
||||
!ifndef FileAssociation_INCLUDED
|
||||
!define FileAssociation_INCLUDED
|
||||
|
||||
!include Util.nsh
|
||||
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!ifndef _FileAssociation_VERBOSE
|
||||
!define _FileAssociation_VERBOSE 3
|
||||
!endif
|
||||
!verbose ${_FileAssociation_VERBOSE}
|
||||
!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
|
||||
!verbose pop
|
||||
|
||||
!macro FileAssociation_VERBOSE _VERBOSE
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!undef _FileAssociation_VERBOSE
|
||||
!define _FileAssociation_VERBOSE ${_VERBOSE}
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
|
||||
!verbose push
|
||||
!verbose ${_FileAssociation_VERBOSE}
|
||||
Push `${_DESCRIPTION}`
|
||||
Push `${_EXTENSION}`
|
||||
Push `${_EXECUTABLE}`
|
||||
${CallArtificialFunction} RegisterExtension_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
|
||||
!verbose push
|
||||
!verbose ${_FileAssociation_VERBOSE}
|
||||
Push `${_EXTENSION}`
|
||||
Push `${_DESCRIPTION}`
|
||||
${CallArtificialFunction} UnRegisterExtension_
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define RegisterExtension `!insertmacro RegisterExtensionCall`
|
||||
!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
|
||||
|
||||
!macro RegisterExtension
|
||||
!macroend
|
||||
|
||||
!macro un.RegisterExtension
|
||||
!macroend
|
||||
|
||||
!macro RegisterExtension_
|
||||
!verbose push
|
||||
!verbose ${_FileAssociation_VERBOSE}
|
||||
|
||||
Exch $R2 ;exe
|
||||
Exch
|
||||
Exch $R1 ;ext
|
||||
Exch
|
||||
Exch 2
|
||||
Exch $R0 ;desc
|
||||
Exch 2
|
||||
Push $0
|
||||
Push $1
|
||||
|
||||
ReadRegStr $1 HKCR $R1 "" ; read current file association
|
||||
StrCmp "$1" "" NoBackup ; is it empty
|
||||
StrCmp "$1" "$R0" NoBackup ; is it our own
|
||||
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
|
||||
NoBackup:
|
||||
WriteRegStr HKCR $R1 "" "$R0" ; set our file association
|
||||
|
||||
ReadRegStr $0 HKCR $R0 ""
|
||||
StrCmp $0 "" 0 Skip
|
||||
WriteRegStr HKCR "$R0" "" "$R0"
|
||||
WriteRegStr HKCR "$R0\shell" "" "open"
|
||||
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
|
||||
Skip:
|
||||
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
|
||||
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
|
||||
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
|
||||
|
||||
Pop $1
|
||||
Pop $0
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
|
||||
!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
|
||||
!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
|
||||
|
||||
!macro UnRegisterExtension
|
||||
!macroend
|
||||
|
||||
!macro un.UnRegisterExtension
|
||||
!macroend
|
||||
|
||||
!macro UnRegisterExtension_
|
||||
!verbose push
|
||||
!verbose ${_FileAssociation_VERBOSE}
|
||||
|
||||
Exch $R1 ;desc
|
||||
Exch
|
||||
Exch $R0 ;ext
|
||||
Exch
|
||||
Push $0
|
||||
Push $1
|
||||
|
||||
ReadRegStr $1 HKCR $R0 ""
|
||||
StrCmp $1 $R1 0 NoOwn ; only do this if we own it
|
||||
ReadRegStr $1 HKCR $R0 "backup_val"
|
||||
StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
|
||||
DeleteRegKey HKCR $R0
|
||||
Goto NoOwn
|
||||
|
||||
Restore:
|
||||
WriteRegStr HKCR $R0 "" $1
|
||||
DeleteRegValue HKCR $R0 "backup_val"
|
||||
DeleteRegKey HKCR $R1 ;Delete key with association name settings
|
||||
|
||||
NoOwn:
|
||||
|
||||
Pop $1
|
||||
Pop $0
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!endif # !FileAssociation_INCLUDED
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
568
dist/windows/strawberry.nsi
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
!define PRODUCT_NAME "Strawberry"
|
||||
!define PRODUCT_PUBLISHER "Strawberry"
|
||||
!define PRODUCT_VERSION_MAJOR 0
|
||||
!define PRODUCT_VERSION_MINOR 2
|
||||
!define PRODUCT_VERSION_PATCH 1
|
||||
!define PRODUCT_DISPLAY_VERSION "0.2.1"
|
||||
!define PRODUCT_DISPLAY_VERSION_SHORT "0.2.1"
|
||||
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
|
||||
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
|
||||
|
||||
; Set Application Capabilities info
|
||||
!define CAPABILITIES_NAME "Strawberry Music Player"
|
||||
!define CAPABILITIES_LOCAL_NAME "Strawberry"
|
||||
!define CAPABILITIES_PROGID "Strawberry Music Player"
|
||||
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
|
||||
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
|
||||
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
|
||||
!define CAPABILITIES_REINSTALL "Command to reinstall"
|
||||
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
|
||||
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
|
||||
|
||||
SetCompressor /SOLID lzma
|
||||
!addplugindir nsisplugins
|
||||
!include "MUI2.nsh"
|
||||
!include "FileAssociation.nsh"
|
||||
!include "Capabilities.nsh"
|
||||
|
||||
!define MUI_ICON "strawberry.ico"
|
||||
|
||||
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||
;!define MUI_FINISHPAGE_RUN
|
||||
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
|
||||
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
|
||||
|
||||
; Installer pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
; Uninstaller pages
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||
|
||||
Name "${PRODUCT_NAME}"
|
||||
OutFile "${PRODUCT_NAME}Setup-0.2.1.exe"
|
||||
InstallDir "${PRODUCT_INSTALL_DIR}"
|
||||
|
||||
; Get the path where Strawberry was installed previously and set it as default path
|
||||
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||
|
||||
ShowInstDetails show
|
||||
ShowUnInstDetails show
|
||||
RequestExecutionLevel admin
|
||||
;RequestExecutionLevel user
|
||||
|
||||
; Check for previous installation, and call the uninstaller if any
|
||||
Function CheckPreviousInstall
|
||||
|
||||
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||
StrCmp $R0 "" done
|
||||
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
|
||||
previous version or `Cancel` to cancel this upgrade." \
|
||||
IDOK uninst
|
||||
Abort
|
||||
; Run the uninstaller
|
||||
uninst:
|
||||
ClearErrors
|
||||
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
|
||||
|
||||
done:
|
||||
|
||||
FunctionEnd
|
||||
|
||||
Function .onInit
|
||||
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
|
||||
Call CheckPreviousInstall
|
||||
|
||||
FunctionEnd
|
||||
|
||||
;!define LVM_GETITEMCOUNT 0x1004
|
||||
!define LVM_GETITEMTEXT 0x102D
|
||||
|
||||
Function DumpLog
|
||||
Exch $5
|
||||
Push $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $6
|
||||
|
||||
FindWindow $0 "#32770" "" $HWNDPARENT
|
||||
GetDlgItem $0 $0 1016
|
||||
StrCmp $0 0 exit
|
||||
FileOpen $5 $5 "w"
|
||||
StrCmp $5 "" exit
|
||||
SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
|
||||
System::Alloc ${NSIS_MAX_STRLEN}
|
||||
Pop $3
|
||||
StrCpy $2 0
|
||||
System::Call "*(i, i, i, i, i, i, i, i, i) i \
|
||||
(0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
|
||||
loop: StrCmp $2 $6 done
|
||||
System::Call "User32::SendMessageA(i, i, i, i) i \
|
||||
($0, ${LVM_GETITEMTEXT}, $2, r1)"
|
||||
System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
|
||||
FileWrite $5 "$4$\r$\n"
|
||||
IntOp $2 $2 + 1
|
||||
Goto loop
|
||||
done:
|
||||
FileClose $5
|
||||
System::Free $1
|
||||
System::Free $3
|
||||
exit:
|
||||
Pop $6
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Pop $0
|
||||
Exch $5
|
||||
FunctionEnd
|
||||
|
||||
;Function RunStrawberry
|
||||
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
|
||||
;FunctionEnd
|
||||
|
||||
Section "Delete old files" oldfiles
|
||||
SectionEnd
|
||||
|
||||
Section "Strawberry" Strawberry
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
File "strawberry.exe"
|
||||
File "strawberry-tagreader.exe"
|
||||
File "strawberry.ico"
|
||||
|
||||
File "libbz2.dll"
|
||||
File "libcdio-16.dll"
|
||||
File "libchromaprint.dll"
|
||||
File "libcrypto-1_1.dll"
|
||||
File "libfaad-2.dll"
|
||||
File "libffi-6.dll"
|
||||
File "libFLAC-8.dll"
|
||||
File "libfreetype-6.dll"
|
||||
File "libgcc_s_sjlj-1.dll"
|
||||
File "libgio-2.0-0.dll"
|
||||
File "libglib-2.0-0.dll"
|
||||
File "libgmodule-2.0-0.dll"
|
||||
File "libgobject-2.0-0.dll"
|
||||
File "libgstapp-1.0-0.dll"
|
||||
File "libgstaudio-1.0-0.dll"
|
||||
File "libgstbase-1.0-0.dll"
|
||||
File "libgstfft-1.0-0.dll"
|
||||
File "libgstpbutils-1.0-0.dll"
|
||||
File "libgstreamer-1.0-0.dll"
|
||||
File "libgstriff-1.0-0.dll"
|
||||
File "libgstrtp-1.0-0.dll"
|
||||
File "libgstrtsp-1.0-0.dll"
|
||||
File "libgstsdp-1.0-0.dll"
|
||||
File "libgsttag-1.0-0.dll"
|
||||
File "libgstvideo-1.0-0.dll"
|
||||
File "libharfbuzz-0.dll"
|
||||
File "libiconv-2.dll"
|
||||
File "libintl-8.dll"
|
||||
File "libjpeg-9.dll"
|
||||
File "liblastfm5.dll"
|
||||
File "libmp3lame-0.dll"
|
||||
File "libogg-0.dll"
|
||||
File "libopus-0.dll"
|
||||
File "libpcre-1.dll"
|
||||
File "libpcre2-16-0.dll"
|
||||
File "libpng16-16.dll"
|
||||
File "libprotobuf-15.dll"
|
||||
File "libspeex-1.dll"
|
||||
File "libsqlite3-0.dll"
|
||||
File "libssl-1_1.dll"
|
||||
File "libstdc++-6.dll"
|
||||
File "libtag.dll"
|
||||
File "libvorbis-0.dll"
|
||||
File "libvorbisenc-2.dll"
|
||||
File "libwavpack-1.dll"
|
||||
File "libwinpthread-1.dll"
|
||||
File "Qt5Concurrent.dll"
|
||||
File "Qt5Core.dll"
|
||||
File "Qt5Gui.dll"
|
||||
File "Qt5Network.dll"
|
||||
File "Qt5Sql.dll"
|
||||
File "Qt5Widgets.dll"
|
||||
File "Qt5Xml.dll"
|
||||
File "zlib1.dll"
|
||||
File "libxine-2.dll"
|
||||
File "libmpcdec-5.dll"
|
||||
File "libtheora-0.dll"
|
||||
File "libfftw3-3.dll"
|
||||
|
||||
; Register Strawberry with Default Programs
|
||||
Var /GLOBAL AppIcon
|
||||
Var /GLOBAL AppExe
|
||||
StrCpy $AppExe "$INSTDIR\strawberry.exe"
|
||||
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
|
||||
|
||||
${RegisterCapabilities}
|
||||
|
||||
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
|
||||
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
|
||||
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
|
||||
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
|
||||
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
|
||||
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
|
||||
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
|
||||
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
|
||||
|
||||
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
|
||||
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
|
||||
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
|
||||
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
|
||||
|
||||
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
|
||||
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
|
||||
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
|
||||
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
|
||||
|
||||
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
|
||||
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Qt Platforms" platforms
|
||||
SetOutPath "$INSTDIR\platforms"
|
||||
File "/oname=qwindows.dll" "platforms\qwindows.dll"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Qt SQL Drivers" sqldrivers
|
||||
SetOutPath "$INSTDIR\sqldrivers"
|
||||
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Qt image format plugins" imageformats
|
||||
SetOutPath "$INSTDIR\imageformats"
|
||||
File "/oname=qgif.dll" "imageformats\qgif.dll"
|
||||
File "/oname=qico.dll" "imageformats\qico.dll"
|
||||
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Gstreamer plugins" gstreamer-plugins
|
||||
SetOutPath "$INSTDIR\gstreamer-plugins"
|
||||
|
||||
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
||||
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
|
||||
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
|
||||
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
|
||||
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
|
||||
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
|
||||
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
|
||||
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
|
||||
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
||||
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
||||
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
|
||||
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
|
||||
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
||||
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
||||
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
||||
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
|
||||
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
|
||||
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
|
||||
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
|
||||
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
|
||||
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
|
||||
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
|
||||
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
||||
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
||||
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
||||
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Xine plugins" xine-plugins
|
||||
SetOutPath "$INSTDIR\xine-plugins"
|
||||
File "/oname=xineplug_ao_out_directx2.dll" "xine-plugins\xineplug_ao_out_directx2.dll"
|
||||
File "/oname=xineplug_ao_out_directx.dll" "xine-plugins\xineplug_ao_out_directx.dll"
|
||||
File "/oname=xineplug_decode_dts.dll" "xine-plugins\xineplug_decode_dts.dll"
|
||||
File "/oname=xineplug_decode_dvaudio.dll" "xine-plugins\xineplug_decode_dvaudio.dll"
|
||||
File "/oname=xineplug_decode_faad.dll" "xine-plugins\xineplug_decode_faad.dll"
|
||||
File "/oname=xineplug_decode_gsm610.dll" "xine-plugins\xineplug_decode_gsm610.dll"
|
||||
File "/oname=xineplug_decode_lpcm.dll" "xine-plugins\xineplug_decode_lpcm.dll"
|
||||
File "/oname=xineplug_decode_mad.dll" "xine-plugins\xineplug_decode_mad.dll"
|
||||
File "/oname=xineplug_decode_mpc.dll" "xine-plugins\xineplug_decode_mpc.dll"
|
||||
File "/oname=xineplug_decode_mpeg2.dll" "xine-plugins\xineplug_decode_mpeg2.dll"
|
||||
File "/oname=xineplug_dmx_asf.dll" "xine-plugins\xineplug_dmx_asf.dll"
|
||||
File "/oname=xineplug_dmx_audio.dll" "xine-plugins\xineplug_dmx_audio.dll"
|
||||
File "/oname=xineplug_dmx_playlist.dll" "xine-plugins\xineplug_dmx_playlist.dll"
|
||||
File "/oname=xineplug_dmx_slave.dll" "xine-plugins\xineplug_dmx_slave.dll"
|
||||
File "/oname=xineplug_flac.dll" "xine-plugins\xineplug_flac.dll"
|
||||
File "/oname=xineplug_wavpack.dll" "xine-plugins\xineplug_wavpack.dll"
|
||||
File "/oname=xineplug_xiph.dll" "xine-plugins\xineplug_xiph.dll"
|
||||
File "/oname=xineplug_inp_cdda.dll" "xine-plugins\xineplug_inp_cdda.dll"
|
||||
|
||||
File "/oname=xineplug_post_audio_filters.dll" "xine-plugins\xineplug_post_audio_filters.dll"
|
||||
File "/oname=xineplug_post_goom.dll" "xine-plugins\xineplug_post_goom.dll"
|
||||
File "/oname=xineplug_post_mosaico.dll" "xine-plugins\xineplug_post_mosaico.dll"
|
||||
File "/oname=xineplug_post_planar.dll" "xine-plugins\xineplug_post_planar.dll"
|
||||
File "/oname=xineplug_post_switch.dll" "xine-plugins\xineplug_post_switch.dll"
|
||||
File "/oname=xineplug_post_tvtime.dll" "xine-plugins\xineplug_post_tvtime.dll"
|
||||
File "/oname=xineplug_post_visualizations.dll" "xine-plugins\xineplug_post_visualizations.dll"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Start menu items" startmenu
|
||||
; Create Start Menu folders and shortcuts.
|
||||
SetShellVarContext all
|
||||
|
||||
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstaller"
|
||||
; Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
|
||||
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
|
||||
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
|
||||
StrCpy $0 "$EXEDIR\install.log"
|
||||
Push $0
|
||||
Call DumpLog
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
; Kill strawberry.exe if it's running
|
||||
; This calling convention is retarded...
|
||||
;StrCpy $0 "strawberry.exe"
|
||||
;KillProc::FindProcesses
|
||||
;StrCmp $1 "-1" wooops
|
||||
|
||||
;StrCmp $0 "0" completed
|
||||
|
||||
;DetailPrint "Killing running strawberry.exe..."
|
||||
|
||||
;StrCpy $0 "strawberry.exe"
|
||||
;KillProc::KillProcesses
|
||||
;StrCmp $1 "-1" wooops
|
||||
|
||||
;Sleep 2000
|
||||
;Goto completed
|
||||
|
||||
;wooops:
|
||||
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
|
||||
;Abort
|
||||
|
||||
;completed:
|
||||
|
||||
; Delete all the files
|
||||
|
||||
;Delete "$EXEDIR\install.log"
|
||||
|
||||
Delete "$INSTDIR\strawberry.ico"
|
||||
Delete "$INSTDIR\strawberry.exe"
|
||||
Delete "$INSTDIR\strawberry-tagreader.exe"
|
||||
|
||||
Delete "$INSTDIR\libbz2.dll"
|
||||
Delete "$INSTDIR\libcdio-16.dll"
|
||||
Delete "$INSTDIR\libchromaprint.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1.dll"
|
||||
Delete "$INSTDIR\libfaad-2.dll"
|
||||
Delete "$INSTDIR\libffi-6.dll"
|
||||
Delete "$INSTDIR\libFLAC-8.dll"
|
||||
Delete "$INSTDIR\libfreetype-6.dll"
|
||||
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||
Delete "$INSTDIR\libgobject-2.0-0.dll"
|
||||
Delete "$INSTDIR\libgstapp-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstbase-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstfft-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstriff-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgsttag-1.0-0.dll"
|
||||
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
|
||||
Delete "$INSTDIR\libharfbuzz-0.dll"
|
||||
Delete "$INSTDIR\libiconv-2.dll"
|
||||
Delete "$INSTDIR\libintl-8.dll"
|
||||
Delete "$INSTDIR\libjpeg-9.dll"
|
||||
Delete "$INSTDIR\liblastfm5.dll"
|
||||
Delete "$INSTDIR\libmp3lame-0.dll"
|
||||
Delete "$INSTDIR\libogg-0.dll"
|
||||
Delete "$INSTDIR\libopus-0.dll"
|
||||
Delete "$INSTDIR\libpcre-1.dll"
|
||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||
Delete "$INSTDIR\libpng16-16.dll"
|
||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
||||
Delete "$INSTDIR\libspeex-1.dll"
|
||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||
Delete "$INSTDIR\libssl-1_1.dll"
|
||||
Delete "$INSTDIR\libstdc++-6.dll"
|
||||
Delete "$INSTDIR\libtag.dll"
|
||||
Delete "$INSTDIR\libvorbis-0.dll"
|
||||
Delete "$INSTDIR\libvorbisenc-2.dll"
|
||||
Delete "$INSTDIR\libwavpack-1.dll"
|
||||
Delete "$INSTDIR\libwinpthread-1.dll"
|
||||
Delete "$INSTDIR\Qt5Concurrent.dll"
|
||||
Delete "$INSTDIR\Qt5Core.dll"
|
||||
Delete "$INSTDIR\Qt5Gui.dll"
|
||||
Delete "$INSTDIR\Qt5Network.dll"
|
||||
Delete "$INSTDIR\Qt5Sql.dll"
|
||||
Delete "$INSTDIR\Qt5Widgets.dll"
|
||||
Delete "$INSTDIR\Qt5Xml.dll"
|
||||
Delete "$INSTDIR\zlib1.dll"
|
||||
Delete "$INSTDIR\libxine-2.dll"
|
||||
Delete "$INSTDIR\libmpcdec-5.dll"
|
||||
Delete "$INSTDIR\libtheora-0.dll"
|
||||
Delete "$INSTDIR\libfftw3-3.dll"
|
||||
|
||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||
|
||||
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||
Delete "$INSTDIR\imageformats\qico.dll"
|
||||
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
||||
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
||||
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
||||
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx2.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_dts.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_dvaudio.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_faad.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_gsm610.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_lpcm.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_mad.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpc.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpeg2.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_dmx_asf.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_dmx_audio.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_dmx_playlist.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_dmx_slave.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_flac.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_wavpack.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_xiph.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_inp_cdda.dll"
|
||||
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_audio_filters.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_goom.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_mosaico.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_planar.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_switch.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_tvtime.dll"
|
||||
Delete "$INSTDIR\xine-plugins\xineplug_post_visualizations.dll"
|
||||
|
||||
Delete "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Remove the installation folders.
|
||||
RMDir "$INSTDIR\platforms"
|
||||
RMDir "$INSTDIR\sqldrivers"
|
||||
RMDir "$INSTDIR\imageformats"
|
||||
RMDir "$INSTDIR\gstreamer-plugins"
|
||||
RMDir "$INSTDIR\xine-plugins"
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
; Remove the Shortcuts
|
||||
SetShellVarContext all
|
||||
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
|
||||
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
|
||||
; Remove the entry from 'installed programs list'
|
||||
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
|
||||
|
||||
; Unregister from Default Programs
|
||||
${UnRegisterCapabilities}
|
||||
|
||||
SectionEnd
|
||||
@@ -1,7 +1,7 @@
|
||||
strawberry ICON "${CMAKE_CURRENT_SOURCE_DIR}/../dist/strawberry.ico"
|
||||
strawberry ICON "${CMAKE_CURRENT_SOURCE_DIR}/../dist/windows/strawberry.ico"
|
||||
1 VERSIONINFO
|
||||
FILEVERSION ${STRAWBERRY_VERSION_MAJOR},${STRAWBERRY_VERSION_MINOR},0,0
|
||||
PRODUCTVERSION ${STRAWBERRY_VERSION_MAJOR},${STRAWBERRY_VERSION_MINOR},0,0
|
||||
FILEVERSION ${STRAWBERRY_VERSION_MAJOR},${STRAWBERRY_VERSION_MINOR},${STRAWBERRY_VERSION_PATCH}
|
||||
PRODUCTVERSION ${STRAWBERRY_VERSION_MAJOR},${STRAWBERRY_VERSION_MINOR},${STRAWBERRY_VERSION_PATCH}
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
@@ -11,7 +11,7 @@ BEGIN
|
||||
VALUE "FileDescription", "Strawberry Music Player"
|
||||
VALUE "FileVersion", "${STRAWBERRY_VERSION_DISPLAY}"
|
||||
VALUE "InternalName", "strawberry"
|
||||
VALUE "LegalCopyright", "David Sansome"
|
||||
VALUE "LegalCopyright", "David Sansome / Jonas Kvinge"
|
||||
VALUE "OriginalFilename", "strawberry.exe"
|
||||
VALUE "ProductName", "Strawberry"
|
||||
VALUE "ProductVersion", "${STRAWBERRY_VERSION_DISPLAY}"
|
||||
@@ -38,4 +38,4 @@ target_link_libraries(libstrawberry-common
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
QT5_USE_MODULES(libstrawberry-common Core Network)
|
||||
target_link_libraries(libstrawberry-common Qt5::Core Qt5::Network)
|
||||
|
||||
@@ -44,6 +44,7 @@ static Level sDefaultLevel = Level_Debug;
|
||||
static QMap<QString, Level>* sClassLevels = nullptr;
|
||||
static QIODevice *sNullDevice = nullptr;
|
||||
|
||||
//const char* kDefaultLogLevels = "*:3";
|
||||
const char* kDefaultLogLevels = "GstEnginePipeline:2,*:3";
|
||||
|
||||
static const char *kMessageHandlerMagic = "__logging_message__";
|
||||
@@ -238,7 +239,7 @@ QString LinuxDemangle(const QString &symbol) {
|
||||
}
|
||||
|
||||
QString DemangleSymbol(const QString &symbol) {
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
return DarwinDemangle(symbol);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return LinuxDemangle(symbol);
|
||||
|
||||
@@ -228,7 +228,7 @@ void WorkerPool<HandlerType>::DoStart() {
|
||||
|
||||
QStringList search_path;
|
||||
search_path << qApp->applicationDirPath();
|
||||
#ifdef Q_OS_MAC
|
||||
#ifdef Q_OS_MACOS
|
||||
search_path << qApp->applicationDirPath() + "/../PlugIns";
|
||||
#endif
|
||||
|
||||
|
||||
@@ -45,9 +45,5 @@ if(APPLE)
|
||||
)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT APPLE)
|
||||
# macdeploy.py takes care of this on mac
|
||||
install(TARGETS strawberry-tagreader
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
endif(NOT APPLE)
|
||||
|
||||
install(TARGETS strawberry-tagreader RUNTIME DESTINATION bin)
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
# along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Woverloaded-virtual -Wno-sign-compare -Wno-deprecated-declarations -Wno-unused-local-typedefs -fpermissive --std=c++0x -U__STRICT_ANSI__")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Woverloaded-virtual -Wno-sign-compare -Wno-deprecated-declarations -Wno-unused-local-typedefs -fpermissive --std=c++11 -U__STRICT_ANSI__")
|
||||
|
||||
option(BUILD_WERROR "Build with -Werror" ON)
|
||||
|
||||
@@ -27,31 +28,43 @@ if(BUILD_WERROR)
|
||||
endif (LINUX)
|
||||
endif(BUILD_WERROR)
|
||||
|
||||
# Set up definitions and paths
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if(WIN32)
|
||||
include_directories(../3rdparty/qtwin)
|
||||
endif(WIN32)
|
||||
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
add_definitions(-DQT_USE_QSTRINGBUILDER)
|
||||
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
|
||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
||||
|
||||
if(ENABLE_IMOBILEDEVICE AND IMOBILEDEVICE_VERSION VERSION_GREATER 1.1.1)
|
||||
set(IMOBILEDEVICE_USES_UDIDS ON)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
|
||||
include_directories(${GOBJECT_INCLUDE_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${LIBXML_INCLUDE_DIRS})
|
||||
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
|
||||
if(HAVE_GSTREAMER)
|
||||
link_directories(${GSTREAMER_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(HAVE_PHONON)
|
||||
include_directories(${PHONON_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||
|
||||
include_directories(${SHA2_INCLUDE_DIRS})
|
||||
include_directories(${QTSINGLEAPPLICATION_INCLUDE_DIRS})
|
||||
include_directories(${QXT_INCLUDE_DIRS})
|
||||
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
|
||||
|
||||
find_package(OpenGL)
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
|
||||
if(HAVE_LIBLASTFM)
|
||||
include_directories(${LASTFM5_INCLUDE_DIRS})
|
||||
@@ -61,8 +74,10 @@ include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-common)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader)
|
||||
include_directories(${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader)
|
||||
|
||||
include(../cmake/AddEngine.cmake)
|
||||
include(../cmake/ParseArguments.cmake)
|
||||
# Windows
|
||||
if (WIN32)
|
||||
include_directories(../3rdparty/qtwin)
|
||||
endif (WIN32)
|
||||
|
||||
set(SOURCES
|
||||
core/mainwindow.cpp
|
||||
@@ -164,7 +179,6 @@ set(SOURCES
|
||||
covermanager/albumcovermanager.cpp
|
||||
covermanager/albumcovermanagerlist.cpp
|
||||
covermanager/albumcoverloader.cpp
|
||||
covermanager/albumcoverloaderoptions.cpp
|
||||
covermanager/albumcoverfetcher.cpp
|
||||
covermanager/albumcoverfetchersearch.cpp
|
||||
covermanager/albumcoversearcher.cpp
|
||||
@@ -402,7 +416,6 @@ set(HEADERS
|
||||
|
||||
device/connecteddevice.h
|
||||
device/devicedatabasebackend.h
|
||||
device/devicekitlister.h
|
||||
device/devicelister.h
|
||||
device/devicemanager.h
|
||||
device/deviceproperties.h
|
||||
@@ -470,29 +483,38 @@ set(OTHER_SOURCES)
|
||||
|
||||
option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
|
||||
|
||||
# Engines
|
||||
# ALSA
|
||||
optional_source(HAVE_ALSA
|
||||
SOURCES
|
||||
engine/alsadevicefinder.cpp
|
||||
)
|
||||
|
||||
set(GST_ENGINE_SRC engine/gstengine.cpp engine/gstenginepipeline.cpp engine/gstelementdeleter.cpp)
|
||||
set(GST_ENGINE_MOC engine/gstengine.h engine/gstenginepipeline.h engine/gstelementdeleter.h)
|
||||
set(GST_ENGINE_LIB GSTREAMER GSTREAMER_BASE GSTREAMER_APP GSTREAMER_AUDIO GSTREAMER_TAG GSTREAMER_PBUTILS)
|
||||
#set(GST_ENGINE_LIB gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 streamer-audio-1.0 gstreamer-tag-1.0 gstreamer-pbutils-1.0)
|
||||
#set(GST_ENGINE_LIB ${GSTREAMER_BASE_LIBRARIES} ${GSTREAMER_LIBRARIES} ${GSTREAMER_APP_LIBRARIES} ${GSTREAMER_TAG_LIBRARIES} ${GSTREAMER_PBUTILS_LIBRARIES})
|
||||
# X11
|
||||
optional_source(HAVE_X11 SOURCES widgets/osd_x11.cpp)
|
||||
|
||||
set(XINE_ENGINE_SRC engine/xineengine.cpp engine/xinescope.c)
|
||||
set(XINE_ENGINE_MOC engine/xineengine.h)
|
||||
# GStreamer
|
||||
optional_source(HAVE_GSTREAMER
|
||||
SOURCES engine/gstengine.cpp engine/gstenginepipeline.cpp engine/gstelementdeleter.cpp
|
||||
HEADERS engine/gstengine.h engine/gstenginepipeline.h engine/gstelementdeleter.h
|
||||
)
|
||||
|
||||
set(VLC_ENGINE_SRC engine/vlcengine.cpp)
|
||||
set(VLC_ENGINE_MOC engine/vlcengine.h)
|
||||
# Xine
|
||||
optional_source(HAVE_XINE
|
||||
SOURCES engine/xineengine.cpp engine/xinescope.c engine/xinefader.cpp
|
||||
HEADERS engine/xineengine.h
|
||||
)
|
||||
|
||||
set(PHONON_ENGINE_SRC engine/phononengine.cpp)
|
||||
set(PHONON_ENGINE_MOC engine/phononengine.h)
|
||||
# VLC
|
||||
optional_source(HAVE_VLC
|
||||
SOURCES engine/vlcengine.cpp
|
||||
HEADERS engine/vlcengine.h
|
||||
)
|
||||
|
||||
add_engine(gstreamer GSTREAMER "${GST_ENGINE_LIB}" "${GST_ENGINE_SRC}" "${GST_ENGINE_MOC}" ON)
|
||||
add_engine(xine XINE LIBXINE "${XINE_ENGINE_SRC}" "${XINE_ENGINE_MOC}" OFF)
|
||||
add_engine(vlc VLC LIBVLC "${VLC_ENGINE_SRC}" "${VLC_ENGINE_MOC}" OFF)
|
||||
add_engine(phonon PHONON PHONON "${PHONON_ENGINE_SRC}" "${PHONON_ENGINE_MOC}" OFF)
|
||||
|
||||
print_engines()
|
||||
# Phonon
|
||||
optional_source(HAVE_PHONON
|
||||
SOURCES engine/phononengine.cpp
|
||||
HEADERS engine/phononengine.h
|
||||
)
|
||||
|
||||
# Lastfm
|
||||
optional_source(HAVE_LIBLASTFM
|
||||
@@ -503,59 +525,8 @@ optional_source(HAVE_LIBLASTFM
|
||||
covermanager/lastfmcoverprovider.h
|
||||
)
|
||||
|
||||
# Platform specific - Linux
|
||||
optional_source(LINUX
|
||||
SOURCES
|
||||
engine/alsadevicefinder.cpp
|
||||
)
|
||||
|
||||
# Platform specific - OS X
|
||||
optional_source(APPLE
|
||||
SOURCES
|
||||
core/mac_startup.mm
|
||||
core/macsystemtrayicon.mm
|
||||
core/macscreensaver.cpp
|
||||
core/macfslistener.mm
|
||||
core/scoped_nsautorelease_pool.mm
|
||||
widgets/osd_mac.mm
|
||||
engine/osxdevicefinder.cpp
|
||||
device/macdevicelister.mm
|
||||
globalshortcuts/shortcutgrabber.mm
|
||||
globalshortcuts/macglobalshortcutbackend.mm
|
||||
globalshortcuts/globalshortcutgrabber.mm
|
||||
HEADERS
|
||||
core/mac_startup.h
|
||||
core/macsystemtrayicon.h
|
||||
core/macscreensaver.h
|
||||
core/macfslistener.h
|
||||
core/mac_utilities.h
|
||||
core/mac_delegate.h
|
||||
engine/osxdevicefinder.h
|
||||
device/macdevicelister.h
|
||||
globalshortcuts/macglobalshortcutbackend.h
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
optional_source(HAVE_LIBMTP
|
||||
SOURCES
|
||||
device/macdevicelister.mm
|
||||
HEADERS
|
||||
device/macdevicelister.h
|
||||
)
|
||||
endif()
|
||||
|
||||
# Platform specific - Windows
|
||||
optional_source(WIN32
|
||||
SOURCES
|
||||
engine/directsounddevicefinder.cpp
|
||||
widgets/osd_win.cpp
|
||||
)
|
||||
|
||||
# Platform specific - X11
|
||||
optional_source(LINUX SOURCES widgets/osd_x11.cpp)
|
||||
|
||||
# DBUS and MPRIS - Linux specific
|
||||
if(HAVE_DBUS)
|
||||
# DBUS and MPRIS - Unix specific
|
||||
if(UNIX AND HAVE_DBUS)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
|
||||
|
||||
# MPRIS DBUS interfaces
|
||||
@@ -665,7 +636,7 @@ if(HAVE_DBUS)
|
||||
dbus/udisks2job)
|
||||
endif(HAVE_UDISKS2)
|
||||
|
||||
endif(HAVE_DBUS)
|
||||
endif(UNIX AND HAVE_DBUS)
|
||||
|
||||
optional_source(HAVE_DBUS
|
||||
SOURCES
|
||||
@@ -677,15 +648,16 @@ optional_source(HAVE_DBUS
|
||||
core/mpris2.h
|
||||
)
|
||||
|
||||
optional_source(HAVE_DEVICEKIT
|
||||
SOURCES device/devicekitlister.cpp
|
||||
HEADERS device/devicekitlister.h
|
||||
)
|
||||
|
||||
optional_source(HAVE_UDISKS2
|
||||
SOURCES device/udisks2lister.cpp
|
||||
HEADERS device/udisks2lister.h
|
||||
)
|
||||
if(HAVE_DBUS)
|
||||
optional_source(HAVE_DEVICEKIT
|
||||
SOURCES device/devicekitlister.cpp
|
||||
HEADERS device/devicekitlister.h
|
||||
)
|
||||
optional_source(HAVE_UDISKS2
|
||||
SOURCES device/udisks2lister.cpp
|
||||
HEADERS device/udisks2lister.h
|
||||
)
|
||||
endif()
|
||||
|
||||
# Libgpod device backend
|
||||
optional_source(HAVE_LIBGPOD
|
||||
@@ -744,6 +716,7 @@ optional_source(HAVE_LIBPULSE
|
||||
engine/pulsedevicefinder.cpp
|
||||
)
|
||||
|
||||
# MusicBrainz, Organise and transcode require GStreamer
|
||||
optional_source(HAVE_GSTREAMER
|
||||
SOURCES
|
||||
core/organise.cpp
|
||||
@@ -802,7 +775,40 @@ optional_source(HAVE_AUDIOCD
|
||||
device/cddasongloader.h
|
||||
UI
|
||||
)
|
||||
endif(HAVE_GSTREAMER)
|
||||
endif()
|
||||
|
||||
# Platform specific - macOS
|
||||
optional_source(APPLE
|
||||
SOURCES
|
||||
core/mac_startup.mm
|
||||
core/macsystemtrayicon.mm
|
||||
core/macscreensaver.cpp
|
||||
core/macfslistener.mm
|
||||
widgets/osd_mac.mm
|
||||
engine/osxdevicefinder.cpp
|
||||
globalshortcuts/globalshortcutgrabber.mm
|
||||
globalshortcuts/macglobalshortcutbackend.mm
|
||||
HEADERS
|
||||
core/macsystemtrayicon.h
|
||||
core/macfslistener.h
|
||||
globalshortcuts/macglobalshortcutbackend.h
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
optional_source(HAVE_LIBMTP
|
||||
SOURCES
|
||||
device/macdevicelister.mm
|
||||
HEADERS
|
||||
device/macdevicelister.h
|
||||
)
|
||||
endif()
|
||||
|
||||
# Platform specific - Windows
|
||||
optional_source(WIN32
|
||||
SOURCES
|
||||
engine/directsounddevicefinder.cpp
|
||||
widgets/osd_win.cpp
|
||||
)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
@@ -827,25 +833,39 @@ add_library(strawberry_lib STATIC
|
||||
target_link_libraries(strawberry_lib
|
||||
libstrawberry-common
|
||||
libstrawberry-tagreader
|
||||
#gstafc
|
||||
${GLIB_LIBRARIES}
|
||||
${GIO_LIBRARIES}
|
||||
${SHA2_LIBRARIES}
|
||||
${TAGLIB_LIBRARIES}
|
||||
${GOBJECT_LIBRARIES}
|
||||
${QT_LIBRARIES}
|
||||
${ENGINE_LIBRARIES}
|
||||
${CHROMAPRINT_LIBRARIES}
|
||||
${QTSINGLEAPPLICATION_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${SQLITE_LIBRARIES}
|
||||
${QOCOA_LIBRARIES}
|
||||
z
|
||||
Qocoa
|
||||
)
|
||||
|
||||
if(LINUX)
|
||||
if(HAVE_ALSA)
|
||||
target_link_libraries(strawberry_lib ${ALSA_LIBRARIES})
|
||||
endif(LINUX)
|
||||
endif(HAVE_ALSA)
|
||||
|
||||
if(HAVE_GSTREAMER)
|
||||
target_link_libraries(strawberry_lib ${GSTREAMER_LIBRARIES} ${GSTREAMER_BASE_LIBRARIES} ${GSTREAMER_AUDIO_LIBRARIES} ${GSTREAMER_APP_LIBRARIES} ${GSTREAMER_TAG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_XINE)
|
||||
target_link_libraries(strawberry_lib ${LIBXINE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_VLC)
|
||||
target_link_libraries(strawberry_lib ${LIBVLC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_PHONON)
|
||||
target_link_libraries(strawberry_lib ${PHONON_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_LIBLASTFM)
|
||||
target_link_libraries(strawberry_lib ${LASTFM5_LIBRARIES})
|
||||
@@ -891,6 +911,7 @@ if (APPLE)
|
||||
"-framework IOKit"
|
||||
"-framework ScriptingBridge"
|
||||
)
|
||||
|
||||
target_link_libraries(strawberry_lib ${SPMEDIAKEYTAP_LIBRARIES})
|
||||
if (HAVE_SPARKLE)
|
||||
include_directories(${SPARKLE}/Headers)
|
||||
@@ -910,13 +931,11 @@ if (WIN32)
|
||||
endif (WIN32)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
# Hack: the Gold linker pays attention to the order that libraries are
|
||||
# specified on the link line. -lX11 and -ldl are provided earlier in the link
|
||||
# command but they're actually used by libraries that appear after them, so
|
||||
# they end up getting ignored. This appends them to the very end of the link
|
||||
# line, ensuring they're always used.
|
||||
# Hack: the Gold linker pays attention to the order that libraries are specified on the link line.
|
||||
# -lX11 and -ldl are provided earlier in the link command but they're actually used by libraries that appear after them, so they end up getting ignored.
|
||||
# This appends them to the very end of the link line, ensuring they're always used.
|
||||
find_package(X11)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
if (FREEBSD)
|
||||
target_link_libraries(strawberry_lib ${X11_X11_LIB})
|
||||
else ()
|
||||
target_link_libraries(strawberry_lib ${X11_X11_LIB} ${CMAKE_DL_LIBS})
|
||||
@@ -937,7 +956,7 @@ endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT ENABLE_WIN32_CONSOLE)
|
||||
|
||||
# Resource file for windows
|
||||
if(WIN32)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../dist/windres.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windres.rc)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../dist/windows/windres.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windres.rc)
|
||||
set(STRAWBERRY-WIN32-RESOURCES windres.rc)
|
||||
endif(WIN32)
|
||||
|
||||
@@ -948,9 +967,9 @@ add_executable(strawberry
|
||||
core/main.cpp
|
||||
)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
if(FREEBSD)
|
||||
target_link_libraries(strawberry execinfo)
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
endif()
|
||||
|
||||
target_link_libraries(strawberry
|
||||
strawberry_lib
|
||||
@@ -959,73 +978,10 @@ target_link_libraries(strawberry
|
||||
# macdeploy.py relies on the blob being built first.
|
||||
add_dependencies(strawberry strawberry-tagreader)
|
||||
|
||||
set_target_properties(strawberry PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "../dist/Info.plist"
|
||||
)
|
||||
if (NOT APPLE)
|
||||
install(TARGETS strawberry RUNTIME DESTINATION bin)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
install(FILES ../dist/strawberry.icns
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
|
||||
install(FILES ../dist/qt.conf
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
|
||||
install(FILES ../dist/sparkle_pub.pem
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
|
||||
|
||||
install(DIRECTORY "${QT_QTGUI_LIBRARY_RELEASE}/Versions/Current/Resources/"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources")
|
||||
|
||||
if (HAVE_SPARKLE)
|
||||
install(DIRECTORY "${SPARKLE}/Versions/Current/Resources"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/Sparkle.framework")
|
||||
endif (HAVE_SPARKLE)
|
||||
|
||||
install(FILES "${QT_QTCORE_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtCore.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTGUI_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtGui.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTNETWORK_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtNetwork.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTOPENGL_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtOpenGL.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTSQL_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtSql.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTSVG_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtSvg.framework/Versions/4/Resources")
|
||||
install(FILES "${QT_QTXML_LIBRARY_RELEASE}/Contents/Info.plist"
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/strawberry.app/Contents/Frameworks/QtXml.framework/Versions/4/Resources")
|
||||
|
||||
add_custom_command(TARGET strawberry
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../dist/macdeploy.py ${PROJECT_BINARY_DIR}/strawberry.app -f
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (APPLE_DEVELOPER_ID)
|
||||
add_custom_target(
|
||||
sign
|
||||
COMMAND
|
||||
${PROJECT_SOURCE_DIR}/dist/codesign.py ${APPLE_DEVELOPER_ID} ${PROJECT_BINARY_DIR}/strawberry.app
|
||||
DEPENDS strawberry
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/strawberry-${STRAWBERRY_VERSION_PACKAGE}.dmg
|
||||
${CMAKE_COMMAND} -E remove -f ${PROJECT_BINARY_DIR}/strawberry-${STRAWBERRY_VERSION_PACKAGE}.dmg
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../dist/create-dmg.sh ${PROJECT_BINARY_DIR}/strawberry.app
|
||||
COMMAND ${CMAKE_COMMAND} -E rename
|
||||
${PROJECT_BINARY_DIR}/strawberry.dmg
|
||||
${PROJECT_BINARY_DIR}/strawberry-${STRAWBERRY_VERSION_PACKAGE}.dmg
|
||||
DEPENDS strawberry
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
add_custom_target(dmg
|
||||
DEPENDS ${PROJECT_BINARY_DIR}/strawberry-${STRAWBERRY_VERSION_PACKAGE}.dmg)
|
||||
else (APPLE)
|
||||
install(TARGETS strawberry
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
set_target_properties(strawberry PROPERTIES MACOSX_BUNDLE_INFO_PLIST "../dist/macos/Info.plist")
|
||||
endif (APPLE)
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef Q_WS_MACX
|
||||
#include <OpenGL/gl.h> //included for convenience
|
||||
#include <OpenGL/glu.h> //included for convenience
|
||||
#else
|
||||
#include <GL/gl.h> //included for convenience
|
||||
#include <GL/glu.h> //included for convenience
|
||||
#endif
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
#include "collectionmodel.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
|
||||
const char *Collection::kSongsTable = "songs";
|
||||
const char *Collection::kDirsTable = "directories";
|
||||
const char *Collection::kSubdirsTable = "subdirectories";
|
||||
const char *Collection::kFtsTable = "songs_fts";
|
||||
const char *SCollection::kSongsTable = "songs";
|
||||
const char *SCollection::kDirsTable = "directories";
|
||||
const char *SCollection::kSubdirsTable = "subdirectories";
|
||||
const char *SCollection::kFtsTable = "songs_fts";
|
||||
|
||||
Collection::Collection(Application *app, QObject *parent)
|
||||
SCollection::SCollection(Application *app, QObject *parent)
|
||||
: QObject(parent),
|
||||
app_(app),
|
||||
backend_(nullptr),
|
||||
@@ -63,14 +63,14 @@ Collection::Collection(Application *app, QObject *parent)
|
||||
|
||||
}
|
||||
|
||||
Collection::~Collection() {
|
||||
SCollection::~SCollection() {
|
||||
|
||||
watcher_->deleteLater();
|
||||
watcher_thread_->exit();
|
||||
watcher_thread_->wait(5000 /* five seconds */);
|
||||
}
|
||||
|
||||
void Collection::Init() {
|
||||
void SCollection::Init() {
|
||||
|
||||
watcher_ = new CollectionWatcher;
|
||||
watcher_thread_ = new Thread(this);
|
||||
@@ -98,26 +98,26 @@ void Collection::Init() {
|
||||
backend_->LoadDirectoriesAsync();
|
||||
}
|
||||
|
||||
void Collection::IncrementalScan() { watcher_->IncrementalScanAsync(); }
|
||||
void SCollection::IncrementalScan() { watcher_->IncrementalScanAsync(); }
|
||||
|
||||
void Collection::FullScan() { watcher_->FullScanAsync(); }
|
||||
void SCollection::FullScan() { watcher_->FullScanAsync(); }
|
||||
|
||||
void Collection::PauseWatcher() { watcher_->SetRescanPausedAsync(true); }
|
||||
void SCollection::PauseWatcher() { watcher_->SetRescanPausedAsync(true); }
|
||||
|
||||
void Collection::ResumeWatcher() { watcher_->SetRescanPausedAsync(false); }
|
||||
void SCollection::ResumeWatcher() { watcher_->SetRescanPausedAsync(false); }
|
||||
|
||||
void SCollection::ReloadSettings() {
|
||||
|
||||
void Collection::ReloadSettings() {
|
||||
|
||||
watcher_->ReloadSettingsAsync();
|
||||
|
||||
}
|
||||
|
||||
void Collection::Stopped() {
|
||||
void SCollection::Stopped() {
|
||||
|
||||
CurrentSongChanged(Song());
|
||||
}
|
||||
|
||||
void Collection::CurrentSongChanged(const Song &song) {
|
||||
void SCollection::CurrentSongChanged(const Song &song) {
|
||||
|
||||
TagReaderReply *reply = nullptr;
|
||||
|
||||
@@ -125,21 +125,4 @@ void Collection::CurrentSongChanged(const Song &song) {
|
||||
connect(reply, SIGNAL(Finished(bool)), reply, SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
if (song.filetype() == Song::Type_Asf) {
|
||||
current_wma_song_url_ = song.url();
|
||||
}
|
||||
}
|
||||
|
||||
SongList Collection::FilterCurrentWMASong(SongList songs, Song* queued) {
|
||||
|
||||
for (SongList::iterator it = songs.begin(); it != songs.end(); ) {
|
||||
if (it->url() == current_wma_song_url_) {
|
||||
*queued = *it;
|
||||
it = songs.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return songs;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ class CollectionBackend;
|
||||
class CollectionModel;
|
||||
class CollectionWatcher;
|
||||
|
||||
class Collection : public QObject {
|
||||
class SCollection : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Collection(Application* app, QObject* parent);
|
||||
~Collection();
|
||||
SCollection(Application *app, QObject *parent);
|
||||
~SCollection();
|
||||
|
||||
static const char *kSongsTable;
|
||||
static const char *kDirsTable;
|
||||
@@ -73,9 +73,6 @@ class Collection : public QObject {
|
||||
void CurrentSongChanged(const Song &song);
|
||||
void Stopped();
|
||||
|
||||
private:
|
||||
SongList FilterCurrentWMASong(SongList songs, Song* queued);
|
||||
|
||||
private:
|
||||
Application *app_;
|
||||
CollectionBackend *backend_;
|
||||
@@ -84,10 +81,6 @@ class Collection : public QObject {
|
||||
CollectionWatcher *watcher_;
|
||||
Thread *watcher_thread_;
|
||||
|
||||
// Hack: Gstreamer doesn't cope well with WMA files being rewritten while being played,
|
||||
// so we delay statistics and rating changes until the current song has finished playing.
|
||||
QUrl current_wma_song_url_;
|
||||
|
||||
// DB schema versions which should trigger a full collection rescan (each of those with a short reason why).
|
||||
QHash<int, QString> full_rescan_revisions_;
|
||||
};
|
||||
|
||||
@@ -219,7 +219,8 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
case GroupBy_Genre: key = song.genre(); break;
|
||||
case GroupBy_AlbumArtist: key = song.effective_albumartist(); break;
|
||||
case GroupBy_Year:
|
||||
key = QString::number(qMax(0, song.year())); break;
|
||||
key = QString::number(qMax(0, song.year()));
|
||||
break;
|
||||
case GroupBy_OriginalYear:
|
||||
key = QString::number(qMax(0, song.effective_originalyear()));
|
||||
break;
|
||||
@@ -227,8 +228,7 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
key = PrettyYearAlbum(qMax(0, song.year()), song.album());
|
||||
break;
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
key = PrettyYearAlbum(qMax(0, song.effective_originalyear()),
|
||||
song.album());
|
||||
key = PrettyYearAlbum(qMax(0, song.effective_originalyear()), song.album());
|
||||
break;
|
||||
case GroupBy_FileType:
|
||||
key = song.filetype();
|
||||
@@ -236,6 +236,12 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
case GroupBy_Bitrate:
|
||||
key = song.bitrate();
|
||||
break;
|
||||
case GroupBy_Samplerate:
|
||||
key = song.samplerate();
|
||||
break;
|
||||
case GroupBy_Bitdepth:
|
||||
key = song.bitdepth();
|
||||
break;
|
||||
case GroupBy_None:
|
||||
qLog(Error) << "GroupBy_None";
|
||||
break;
|
||||
@@ -325,6 +331,12 @@ QString CollectionModel::DividerKey(GroupBy type, CollectionItem *item) const {
|
||||
|
||||
case GroupBy_Bitrate:
|
||||
return SortTextForNumber(item->metadata.bitrate());
|
||||
|
||||
case GroupBy_Samplerate:
|
||||
return SortTextForNumber(item->metadata.samplerate());
|
||||
|
||||
case GroupBy_Bitdepth:
|
||||
return SortTextForNumber(item->metadata.bitdepth());
|
||||
|
||||
case GroupBy_None:
|
||||
return QString();
|
||||
@@ -364,6 +376,14 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
|
||||
case GroupBy_Bitrate:
|
||||
if (key == "000") return tr("Unknown");
|
||||
return QString::number(key.toInt()); // To remove leading 0s
|
||||
|
||||
case GroupBy_Samplerate:
|
||||
if (key == "000") return tr("Unknown");
|
||||
return QString::number(key.toInt()); // To remove leading 0s
|
||||
|
||||
case GroupBy_Bitdepth:
|
||||
if (key == "000") return tr("Unknown");
|
||||
return QString::number(key.toInt()); // To remove leading 0s
|
||||
|
||||
case GroupBy_None:
|
||||
// fallthrough
|
||||
@@ -836,6 +856,12 @@ void CollectionModel::InitQuery(GroupBy type, CollectionQuery *q) {
|
||||
case GroupBy_Bitrate:
|
||||
q->SetColumnSpec("DISTINCT bitrate");
|
||||
break;
|
||||
case GroupBy_Samplerate:
|
||||
q->SetColumnSpec("DISTINCT samplerate");
|
||||
break;
|
||||
case GroupBy_Bitdepth:
|
||||
q->SetColumnSpec("DISTINCT bitdepth");
|
||||
break;
|
||||
case GroupBy_None:
|
||||
q->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||
break;
|
||||
@@ -911,6 +937,12 @@ void CollectionModel::FilterQuery(GroupBy type, CollectionItem *item, Collection
|
||||
case GroupBy_Bitrate:
|
||||
q->AddWhere("bitrate", item->key);
|
||||
break;
|
||||
case GroupBy_Samplerate:
|
||||
q->AddWhere("samplerate", item->key);
|
||||
break;
|
||||
case GroupBy_Bitdepth:
|
||||
q->AddWhere("bitdepth", item->key);
|
||||
break;
|
||||
case GroupBy_None:
|
||||
qLog(Error) << "Unknown GroupBy type" << type << "used in filter";
|
||||
break;
|
||||
@@ -936,10 +968,7 @@ CollectionItem *CollectionModel::InitItem(GroupBy type, bool signal, CollectionI
|
||||
CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const SqlRow &row, int container_level) {
|
||||
|
||||
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
||||
int year = 0;
|
||||
int effective_originalyear = 0;
|
||||
int bitrate = 0;
|
||||
int disc = 0;
|
||||
int year(0), effective_originalyear(0), disc(0), bitrate(0), samplerate(0), bitdepth(0);
|
||||
|
||||
switch (type) {
|
||||
case GroupBy_Artist:
|
||||
@@ -972,13 +1001,11 @@ CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool c
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_OriginalYear:
|
||||
year = qMax(0, row.value(0).toInt());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Composer:
|
||||
case GroupBy_Performer:
|
||||
case GroupBy_Grouping:
|
||||
@@ -1006,6 +1033,18 @@ CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool c
|
||||
item->key = QString::number(bitrate);
|
||||
item->sort_text = SortTextForNumber(bitrate) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Samplerate:
|
||||
samplerate = qMax(0, row.value(0).toInt());
|
||||
item->key = QString::number(samplerate);
|
||||
item->sort_text = SortTextForNumber(samplerate) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Bitdepth:
|
||||
bitdepth = qMax(0, row.value(0).toInt());
|
||||
item->key = QString::number(bitdepth);
|
||||
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_None:
|
||||
item->metadata.InitFromQuery(row, true);
|
||||
@@ -1024,10 +1063,7 @@ CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool c
|
||||
CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const Song &s, int container_level) {
|
||||
|
||||
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
||||
int year = 0;
|
||||
int originalyear = 0;
|
||||
int effective_originalyear = 0;
|
||||
int bitrate = 0;
|
||||
int year(0), originalyear(0), effective_originalyear(0), bitrate(0), samplerate(0), bitdepth(0);
|
||||
|
||||
switch (type) {
|
||||
case GroupBy_Artist:
|
||||
@@ -1092,6 +1128,18 @@ CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool cr
|
||||
item->key = QString::number(bitrate);
|
||||
item->sort_text = SortTextForNumber(bitrate) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Samplerate:
|
||||
samplerate = qMax(0, s.samplerate());
|
||||
item->key = QString::number(samplerate);
|
||||
item->sort_text = SortTextForNumber(samplerate) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Bitdepth:
|
||||
bitdepth = qMax(0, s.bitdepth());
|
||||
item->key = QString::number(bitdepth);
|
||||
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_None:
|
||||
item->metadata = s;
|
||||
|
||||
@@ -99,6 +99,8 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
||||
GroupBy_Disc = 12,
|
||||
GroupBy_OriginalYearAlbum = 13,
|
||||
GroupBy_OriginalYear = 14,
|
||||
GroupBy_Samplerate = 15,
|
||||
GroupBy_Bitdepth = 16
|
||||
};
|
||||
|
||||
struct Grouping {
|
||||
|
||||
@@ -230,7 +230,7 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
||||
ScanTransaction transaction(this, dir.id, true);
|
||||
transaction.SetKnownSubdirs(subdirs);
|
||||
transaction.AddToProgressMax(subdirs.count());
|
||||
for (const Subdirectory& subdir : subdirs) {
|
||||
for (const Subdirectory &subdir : subdirs) {
|
||||
if (stop_requested_) return;
|
||||
|
||||
if (scan_on_startup_) ScanSubdirectory(subdir.path, subdir, &transaction);
|
||||
@@ -742,9 +742,9 @@ void CollectionWatcher::ReloadSettings() {
|
||||
}
|
||||
else if (monitor_ && !was_monitoring_before) {
|
||||
// Add all directories to all QFileSystemWatchers again
|
||||
for (const Directory& dir : watched_dirs_.values()) {
|
||||
for (const Directory &dir : watched_dirs_.values()) {
|
||||
SubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
|
||||
for (const Subdirectory& subdir : subdirs) {
|
||||
for (const Subdirectory &subdir : subdirs) {
|
||||
AddWatch(dir, subdir.path);
|
||||
}
|
||||
}
|
||||
@@ -783,12 +783,12 @@ void CollectionWatcher::FullScanNow() { PerformScan(false, true); }
|
||||
|
||||
void CollectionWatcher::PerformScan(bool incremental, bool ignore_mtimes) {
|
||||
|
||||
for (const Directory & dir : watched_dirs_.values()) {
|
||||
for (const Directory &dir : watched_dirs_.values()) {
|
||||
ScanTransaction transaction(this, dir.id, incremental, ignore_mtimes);
|
||||
SubdirectoryList subdirs(transaction.GetAllSubdirs());
|
||||
transaction.AddToProgressMax(subdirs.count());
|
||||
|
||||
for (const Subdirectory & subdir : subdirs) {
|
||||
for (const Subdirectory &subdir : subdirs) {
|
||||
if (stop_requested_) return;
|
||||
|
||||
ScanSubdirectory(subdir.path, subdir, &transaction);
|
||||
|
||||
@@ -96,11 +96,13 @@ GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_Grou
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_YearAlbum, 9));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_OriginalYearAlbum, 10));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitrate, 11));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Disc, 12));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Performer, 13));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Grouping, 14));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Samplerate, 12));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitdepth, 13));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Disc, 14));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Performer, 15));
|
||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Grouping, 16));
|
||||
|
||||
connect(ui_->button_box->button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(Reset()));
|
||||
connect(ui_->buttonbox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(Reset()));
|
||||
|
||||
resize(sizeHint());
|
||||
}
|
||||
@@ -108,23 +110,23 @@ GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_Grou
|
||||
GroupByDialog::~GroupByDialog() {}
|
||||
|
||||
void GroupByDialog::Reset() {
|
||||
ui_->first->setCurrentIndex(2); // Artist
|
||||
ui_->second->setCurrentIndex(1); // Album
|
||||
ui_->third->setCurrentIndex(0); // None
|
||||
ui_->combobox_first->setCurrentIndex(2); // Artist
|
||||
ui_->combobox_second->setCurrentIndex(1); // Album
|
||||
ui_->combobox_third->setCurrentIndex(0); // None
|
||||
}
|
||||
|
||||
void GroupByDialog::accept() {
|
||||
emit Accepted(CollectionModel::Grouping(
|
||||
p_->mapping_.get<tag_index>().find(ui_->first->currentIndex())->group_by,
|
||||
p_->mapping_.get<tag_index>().find(ui_->second->currentIndex())->group_by,
|
||||
p_->mapping_.get<tag_index>().find(ui_->third->currentIndex())->group_by)
|
||||
p_->mapping_.get<tag_index>().find(ui_->combobox_first->currentIndex())->group_by,
|
||||
p_->mapping_.get<tag_index>().find(ui_->combobox_second->currentIndex())->group_by,
|
||||
p_->mapping_.get<tag_index>().find(ui_->combobox_third->currentIndex())->group_by)
|
||||
);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void GroupByDialog::CollectionGroupingChanged(const CollectionModel::Grouping &g) {
|
||||
ui_->first->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[0])->combo_box_index);
|
||||
ui_->second->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[1])->combo_box_index);
|
||||
ui_->third->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[2])->combo_box_index);
|
||||
ui_->combobox_first->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[0])->combo_box_index);
|
||||
ui_->combobox_second->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[1])->combo_box_index);
|
||||
ui_->combobox_third->setCurrentIndex(p_->mapping_.get<tag_group_by>().find(g[2])->combo_box_index);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>354</width>
|
||||
<height>236</height>
|
||||
<height>246</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -19,7 +19,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>You can change the way the songs in the collection are organised.</string>
|
||||
</property>
|
||||
@@ -35,14 +35,14 @@
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="label_first">
|
||||
<property name="text">
|
||||
<string>First level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="first">
|
||||
<widget class="QComboBox" name="combobox_first">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
@@ -103,6 +103,16 @@
|
||||
<string>Bitrate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sample rate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bit depth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disc</string>
|
||||
@@ -121,14 +131,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="label_second">
|
||||
<property name="text">
|
||||
<string>Second level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="second">
|
||||
<widget class="QComboBox" name="combobox_second">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
@@ -189,6 +199,16 @@
|
||||
<string>Bitrate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sample rate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bit depth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disc</string>
|
||||
@@ -207,14 +227,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<widget class="QLabel" name="label_third">
|
||||
<property name="text">
|
||||
<string>Third level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="third">
|
||||
<widget class="QComboBox" name="combobox_third">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
@@ -275,6 +295,16 @@
|
||||
<string>Bitrate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sample rate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bit depth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disc</string>
|
||||
@@ -309,7 +339,7 @@
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="button_box">
|
||||
<widget class="QDialogButtonBox" name="buttonbox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -321,17 +351,17 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>first</tabstop>
|
||||
<tabstop>second</tabstop>
|
||||
<tabstop>third</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
<tabstop>combobox_first</tabstop>
|
||||
<tabstop>combobox_second</tabstop>
|
||||
<tabstop>combobox_third</tabstop>
|
||||
<tabstop>buttonbox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../data/data.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>button_box</sender>
|
||||
<sender>buttonbox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GroupByDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
@@ -347,7 +377,7 @@
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>button_box</sender>
|
||||
<sender>buttonbox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GroupByDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
|
||||
@@ -110,6 +110,12 @@ QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g)
|
||||
case CollectionModel::GroupBy_Bitrate: {
|
||||
return tr("Bitrate");
|
||||
}
|
||||
case CollectionModel::GroupBy_Samplerate: {
|
||||
return tr("Sample rate");
|
||||
}
|
||||
case CollectionModel::GroupBy_Bitdepth: {
|
||||
return tr("Bit depth");
|
||||
}
|
||||
case CollectionModel::GroupBy_Disc: {
|
||||
return tr("Disc");
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
#cmakedefine HAVE_GIO
|
||||
#cmakedefine HAVE_DBUS
|
||||
#cmakedefine HAVE_X11
|
||||
#cmakedefine HAVE_UDISKS2
|
||||
#cmakedefine HAVE_ALSA
|
||||
#cmakedefine HAVE_DEVICEKIT
|
||||
#cmakedefine HAVE_IMOBILEDEVICE
|
||||
#cmakedefine HAVE_LIBARCHIVE
|
||||
|
||||
@@ -74,7 +74,7 @@ class ApplicationImpl {
|
||||
player_([=]() { return new Player(app, app); }),
|
||||
enginedevice_([=]() { return new EngineDevice(app); }),
|
||||
device_manager_([=]() { return new DeviceManager(app, app); }),
|
||||
collection_([=]() { return new Collection(app, app); }),
|
||||
collection_([=]() { return new SCollection(app, app); }),
|
||||
playlist_backend_([=]() {
|
||||
PlaylistBackend *backend = new PlaylistBackend(app, app);
|
||||
app->MoveToThread(backend, database_->thread());
|
||||
@@ -107,7 +107,7 @@ class ApplicationImpl {
|
||||
Lazy<Player> player_;
|
||||
Lazy<EngineDevice> enginedevice_;
|
||||
Lazy<DeviceManager> device_manager_;
|
||||
Lazy<Collection> collection_;
|
||||
Lazy<SCollection> collection_;
|
||||
Lazy<PlaylistBackend> playlist_backend_;
|
||||
Lazy<PlaylistManager> playlist_manager_;
|
||||
Lazy<CoverProviders> cover_providers_;
|
||||
@@ -183,7 +183,7 @@ DeviceManager *Application::device_manager() const {
|
||||
return p_->device_manager_.get();
|
||||
}
|
||||
|
||||
Collection *Application::collection() const { return p_->collection_.get(); }
|
||||
SCollection *Application::collection() const { return p_->collection_.get(); }
|
||||
|
||||
CollectionBackend *Application::collection_backend() const {
|
||||
return collection()->backend();
|
||||
|
||||
@@ -40,7 +40,7 @@ class Database;
|
||||
class EngineDevice;
|
||||
class Player;
|
||||
class Appearance;
|
||||
class Collection;
|
||||
class SCollection;
|
||||
class CollectionBackend;
|
||||
class CollectionModel;
|
||||
class PlaylistBackend;
|
||||
@@ -67,15 +67,15 @@ class Application : public QObject {
|
||||
EngineDevice *enginedevice() const;
|
||||
DeviceManager *device_manager() const;
|
||||
|
||||
Collection *collection() const;
|
||||
|
||||
SCollection *collection() const;
|
||||
|
||||
PlaylistBackend *playlist_backend() const;
|
||||
PlaylistManager *playlist_manager() const;
|
||||
|
||||
CoverProviders *cover_providers() const;
|
||||
AlbumCoverLoader *album_cover_loader() const;
|
||||
CurrentArtLoader *current_art_loader() const;
|
||||
|
||||
|
||||
CollectionBackend *collection_backend() const;
|
||||
CollectionModel *collection_model() const;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ CommandlineOptions::CommandlineOptions(int argc, char* *argv)
|
||||
toggle_pretty_osd_(false),
|
||||
log_levels_(logging::kDefaultLogLevels) {
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
// Remove -psn_xxx option that Mac passes when opened from Finder.
|
||||
RemoveArg("-psn", 1);
|
||||
#endif
|
||||
@@ -167,16 +167,13 @@ bool CommandlineOptions::Parse() {
|
||||
.arg(tr("Skip backwards in playlist"),
|
||||
tr("Skip forwards in playlist"),
|
||||
tr("Set the volume to <value> percent"),
|
||||
tr("Increase the volume by 4%"),
|
||||
tr("Decrease the volume by 4%"),
|
||||
tr("Increase the volume by 4 precent"),
|
||||
tr("Decrease the volume by 4 precent"),
|
||||
tr("Increase the volume by <value> percent"),
|
||||
tr("Decrease the volume by <value> percent"))
|
||||
.arg(tr("Seek the currently playing track to an absolute "
|
||||
"position"),
|
||||
tr("Seek the currently playing track by a relative "
|
||||
"amount"),
|
||||
tr("Restart the track, or play the previous track if "
|
||||
"within 8 seconds of start."),
|
||||
.arg(tr("Seek the currently playing track to an absolute position"),
|
||||
tr("Seek the currently playing track by a relative amount"),
|
||||
tr("Restart the track, or play the previous track if within 8 seconds of start."),
|
||||
tr("Playlist options"),
|
||||
tr("Create a new playlist with files"),
|
||||
tr("Append files/URLs to the playlist"),
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "filesystemwatcherinterface.h"
|
||||
#include "qtfslistener.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
#include "macfslistener.h"
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,7 @@ FileSystemWatcherInterface::FileSystemWatcherInterface(QObject *parent)
|
||||
|
||||
FileSystemWatcherInterface *FileSystemWatcherInterface::Create(QObject *parent) {
|
||||
FileSystemWatcherInterface *ret;
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
ret = new MacFSListener(parent);
|
||||
#else
|
||||
ret = new QtFSListener(parent);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#import <AppKit/NSApplication.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "macglobalshortcutbackend.h"
|
||||
#include "globalshortcuts/macglobalshortcutbackend.h"
|
||||
|
||||
class PlatformInterface;
|
||||
@class SPMediaKeyTap;
|
||||
|
||||
@@ -43,18 +43,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "globalshortcuts.h"
|
||||
#include "mac_delegate.h"
|
||||
#include "mac_startup.h"
|
||||
#include "mac_utilities.h"
|
||||
#include "macglobalshortcutbackend.h"
|
||||
#include "utilities.h"
|
||||
#include "core/logging.h"
|
||||
#include "scoped_cftyperef.h"
|
||||
#include "scoped_nsautorelease_pool.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/scoped_nsautorelease_pool.h"
|
||||
#include "globalshortcuts/globalshortcuts.h"
|
||||
#include "globalshortcuts/macglobalshortcutbackend.h"
|
||||
|
||||
#ifdef HAVE_SPARKLE
|
||||
#import <Sparkle/SUUpdater.h>
|
||||
# import <Sparkle/SUUpdater.h>
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -90,7 +90,7 @@ class MacSystemTrayIconPrivate {
|
||||
// This must be called after our custom NSApplicationDelegate has been set.
|
||||
[(AppDelegate*)([NSApp delegate]) setDockMenu:dock_menu_];
|
||||
|
||||
ClearPlaying();
|
||||
ClearNowPlaying();
|
||||
}
|
||||
|
||||
void AddMenuItem(QAction* action) {
|
||||
@@ -120,8 +120,8 @@ class MacSystemTrayIconPrivate {
|
||||
[dock_menu_ addItem:separator];
|
||||
}
|
||||
|
||||
void ShowPlaying(const QString& artist, const QString& title) {
|
||||
ClearPlaying(); // Makes sure the order is consistent.
|
||||
void ShowNowPlaying(const QString& artist, const QString& title) {
|
||||
ClearNowPlaying(); // Makes sure the order is consistent.
|
||||
[now_playing_artist_ setTitle:
|
||||
[[NSString alloc] initWithUTF8String: artist.toUtf8().constData()]];
|
||||
[now_playing_title_ setTitle:
|
||||
@@ -131,7 +131,7 @@ class MacSystemTrayIconPrivate {
|
||||
artist.isEmpty() && title.isEmpty() ? HideItem(now_playing_) : ShowItem(now_playing_);
|
||||
}
|
||||
|
||||
void ClearPlaying() {
|
||||
void ClearNowPlaying() {
|
||||
// Hiding doesn't seem to work in the dock menu.
|
||||
HideItem(now_playing_);
|
||||
HideItem(now_playing_artist_);
|
||||
@@ -200,10 +200,10 @@ void MacSystemTrayIcon::ActionChanged() {
|
||||
p_->ActionChanged(action);
|
||||
}
|
||||
|
||||
void MacSystemTrayIcon::ClearPlaying() {
|
||||
p_->ClearPlaying();
|
||||
void MacSystemTrayIcon::ClearNowPlaying() {
|
||||
p_->ClearNowPlaying();
|
||||
}
|
||||
|
||||
void MacSystemTrayIcon::SetPlaying(const Song& song, const QString& image_path) {
|
||||
p_->ShowPlaying(song.artist(), song.PrettyTitle());
|
||||
void MacSystemTrayIcon::SetNowPlaying(const Song& song, const QString& image_path) {
|
||||
p_->ShowNowPlaying(song.artist(), song.PrettyTitle());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,15 +22,34 @@
|
||||
#include "config.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <memory>
|
||||
#include <time.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
# include <sys/resource.h>
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#endif // Q_OS_WIN32
|
||||
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QFileDevice>
|
||||
#include <QIODevice>
|
||||
#include <QByteArray>
|
||||
@@ -43,18 +63,7 @@
|
||||
# include <QDBusArgument>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#endif // Q_OS_WIN32
|
||||
#include "main.h"
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
@@ -62,7 +71,7 @@
|
||||
#include "qtsinglecoreapplication.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
#include "mpris.h"
|
||||
# include "mpris.h"
|
||||
#endif
|
||||
#include "utilities.h"
|
||||
#include "metatypes.h"
|
||||
@@ -83,13 +92,13 @@
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
// Do Mac specific startup to get media keys working.
|
||||
// This must go before QApplication initialisation.
|
||||
mac::MacMain();
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN)
|
||||
#if defined(Q_OS_WIN32) || defined(Q_OS_MACOS)
|
||||
QCoreApplication::setApplicationName("Strawberry");
|
||||
QCoreApplication::setOrganizationName("Strawberry");
|
||||
#else
|
||||
@@ -128,13 +137,14 @@ int main(int argc, char* argv[]) {
|
||||
qLog(Info) << "Strawberry is already running - activating existing window";
|
||||
}
|
||||
if (a.sendMessage(options.Serialize(), 5000)) {
|
||||
main_exit_safe(0);
|
||||
return 0;
|
||||
}
|
||||
// Couldn't send the message so start anyway
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
// Must happen after QCoreApplication::setOrganizationName().
|
||||
setenv("XDG_CONFIG_HOME", QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation).toLocal8Bit().constData(), 1);
|
||||
#endif
|
||||
@@ -151,8 +161,8 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
QtSingleApplication a(argc, argv);
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
QCoreApplication::setCollectionPaths(QStringList() << QCoreApplication::applicationDirPath() + "/../PlugIns");
|
||||
#ifdef Q_OS_MACOS
|
||||
//QCoreApplication::setLibraryPaths(QStringList() << QCoreApplication::applicationDirPath() + "/../PlugIns");
|
||||
#endif
|
||||
|
||||
a.setQuitOnLastWindowClosed(false);
|
||||
@@ -162,7 +172,7 @@ int main(int argc, char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_DARWIN
|
||||
#ifndef Q_OS_MACOS
|
||||
// Gnome on Ubuntu has menu icons disabled by default. I think that's a bad idea, and makes some menus in Strawberry look confusing.
|
||||
QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false);
|
||||
#else
|
||||
@@ -171,8 +181,8 @@ int main(int argc, char* argv[]) {
|
||||
QCoreApplication::setAttribute(Qt::AA_NativeWindows, true);
|
||||
#endif
|
||||
|
||||
// Set the permissions on the config file on Unix - it can contain passwords for internet services so it's important that other users can't read it.
|
||||
// On Windows these are stored in the registry instead.
|
||||
// Set the permissions on the config file on Unix - it can contain passwords for internet services so it's important that other users can't read it.
|
||||
// On Windows these are stored in the registry instead.
|
||||
#ifdef Q_OS_UNIX
|
||||
{
|
||||
QSettings s;
|
||||
@@ -209,9 +219,9 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Window
|
||||
MainWindow w(&app, tray_icon.get(), &osd, options);
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
mac::EnableFullScreen(w);
|
||||
#endif // Q_OS_DARWIN
|
||||
#endif // Q_OS_MACOS
|
||||
#ifdef HAVE_GIO
|
||||
ScanGIOModulePath();
|
||||
#endif
|
||||
@@ -222,5 +232,44 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
int ret = a.exec();
|
||||
|
||||
main_exit_safe(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void main_exit_safe(int ret) {
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
bool have_nvidia = false;
|
||||
|
||||
QFile proc_modules("/proc/modules");
|
||||
if (proc_modules.open(QIODevice::ReadOnly)) {
|
||||
forever {
|
||||
QByteArray line = proc_modules.readLine();
|
||||
if (line.startsWith("nvidia ") || line.startsWith("nvidia_")) {
|
||||
have_nvidia = true;
|
||||
}
|
||||
if (proc_modules.atEnd()) break;
|
||||
}
|
||||
proc_modules.close();
|
||||
}
|
||||
|
||||
QFile self_maps("/proc/self/maps");
|
||||
if (self_maps.open(QIODevice::ReadOnly)) {
|
||||
forever {
|
||||
QByteArray line = self_maps.readLine();
|
||||
if (line.startsWith("libnvidia-")) {
|
||||
have_nvidia = true;
|
||||
}
|
||||
if (self_maps.atEnd()) break;
|
||||
}
|
||||
self_maps.close();
|
||||
}
|
||||
|
||||
if (have_nvidia) {
|
||||
qLog(Warning) << "Exiting immediately to work around NVIDIA driver bug.";
|
||||
_exit(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
28
src/core/main.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
int main(int argc, char* argv[]);
|
||||
void main_exit_safe(int ret);
|
||||
|
||||
#endif // MAIN_H
|
||||
@@ -84,7 +84,7 @@
|
||||
#include "dialogs/trackselectiondialog.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
#include "dialogs/organisedialog.h"
|
||||
# include "dialogs/organisedialog.h"
|
||||
#endif
|
||||
#include "widgets/fancytabwidget.h"
|
||||
#include "widgets/playingwidget.h"
|
||||
@@ -127,13 +127,13 @@
|
||||
#include "settings/playlistsettingspage.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "ui/macsystemtrayicon.h"
|
||||
#ifdef Q_OS_MACOS
|
||||
# include "core/macsystemtrayicon.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
// Non exported mac-specific function.
|
||||
void qt_mac_set_dock_menu(QMenu*);
|
||||
#ifdef Q_OS_MACOS
|
||||
// Non exported mac-specific function.
|
||||
void qt_mac_set_dock_menu(QMenu*);
|
||||
#endif
|
||||
|
||||
const char *MainWindow::kSettingsGroup = "MainWindow";
|
||||
@@ -203,7 +203,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
|
||||
// Initialise the UI
|
||||
ui_->setupUi(this);
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
ui_->menu_help->menuAction()->setVisible(false);
|
||||
#endif
|
||||
|
||||
@@ -219,16 +219,15 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker());
|
||||
|
||||
// Add tabs to the fancy tab widget
|
||||
|
||||
ui_->tabs->AddTab(status_view_, IconLoader::Load("strawberry"), tr("Status"));
|
||||
ui_->tabs->AddTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
|
||||
ui_->tabs->AddTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
|
||||
ui_->tabs->AddTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||
ui_->tabs->AddTab(device_view_, IconLoader::Load("device"), tr("Devices"));
|
||||
ui_->tabs->addTab(status_view_, IconLoader::Load("strawberry"), tr("Status"));
|
||||
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
|
||||
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
|
||||
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices"));
|
||||
//ui_->tabs->AddSpacer();
|
||||
|
||||
// Add the now playing widget to the fancy tab widget
|
||||
ui_->tabs->AddBottomWidget(ui_->now_playing);
|
||||
ui_->tabs->addBottomWidget(ui_->now_playing);
|
||||
|
||||
//ui_->tabs->SetBackgroundPixmap(QPixmap(":/pictures/strawberry-background.png"));
|
||||
|
||||
@@ -512,7 +511,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
playlist_menu_->addAction(ui_->action_remove_duplicates);
|
||||
playlist_menu_->addAction(ui_->action_remove_unavailable);
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
ui_->action_shuffle->setShortcut(QKeySequence());
|
||||
#endif
|
||||
|
||||
@@ -526,7 +525,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), playlist_copy_to_device_, SLOT(setDisabled(bool)));
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
mac::SetApplicationHandler(this);
|
||||
#endif
|
||||
// Tray icon
|
||||
@@ -543,7 +542,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
// Windows 7 thumbbar buttons
|
||||
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr); // spacer
|
||||
|
||||
#if (defined(Q_OS_DARWIN) && defined(HAVE_SPARKLE)) || defined(Q_OS_WIN32)
|
||||
#if (defined(Q_OS_MACOS) && defined(HAVE_SPARKLE))
|
||||
// Add check for updates item to application menu.
|
||||
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
||||
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
|
||||
@@ -643,10 +642,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
if (!ui_->splitter->restoreState(settings_.value("splitter_state").toByteArray())) {
|
||||
ui_->splitter->setSizes(QList<int>() << 300 << width() - 300);
|
||||
}
|
||||
ui_->tabs->SetCurrentIndex(settings_.value("current_tab", 1 /* Collection tab */ ).toInt());
|
||||
ui_->tabs->setCurrentIndex(settings_.value("current_tab", 1 /* Collection tab */ ).toInt());
|
||||
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar;
|
||||
ui_->tabs->SetMode(FancyTabWidget::Mode(settings_.value("tab_mode", default_mode).toInt()));
|
||||
file_view_->SetPath(settings_.value("file_path", QDir::homePath()).toString());
|
||||
|
||||
TabSwitched();
|
||||
|
||||
// Users often collapse one side of the splitter by mistake and don't know how to restore it. This must be set after the state is restored above.
|
||||
@@ -661,7 +661,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
ui_->playlist->view()->ReloadSettings();
|
||||
|
||||
|
||||
#ifndef Q_OS_DARWIN
|
||||
#ifndef Q_OS_MACOS
|
||||
QSettings settings;
|
||||
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||
StartupBehaviour behaviour = StartupBehaviour(settings.value("startupbehaviour", Startup_Remember).toInt());
|
||||
@@ -682,7 +682,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
settings_.setValue("hidden", false);
|
||||
show();
|
||||
}
|
||||
#else // Q_OS_DARWIN
|
||||
#else // Q_OS_MACOS
|
||||
// Always show mainwindow on startup on OS X.
|
||||
show();
|
||||
#endif
|
||||
@@ -711,7 +711,7 @@ void MainWindow::ReloadSettings() {
|
||||
|
||||
QSettings settings;
|
||||
|
||||
#ifndef Q_OS_DARWIN
|
||||
#ifndef Q_OS_MACOS
|
||||
|
||||
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||
bool showtrayicon = settings.value("showtrayicon", true).toBool();
|
||||
@@ -729,7 +729,6 @@ void MainWindow::ReloadSettings() {
|
||||
doubleclick_playlist_addmode_ = PlaylistAddBehaviour(settings.value("doubleclick_playlist_addmode", PlaylistAddBehaviour_Play).toInt());
|
||||
menu_playmode_ = PlayBehaviour(settings.value("menu_playmode", PlayBehaviour_IfStopped).toInt());
|
||||
settings.endGroup();
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::ReloadAllSettings() {
|
||||
@@ -742,7 +741,6 @@ void MainWindow::ReloadAllSettings() {
|
||||
app_->player()->ReloadSettings();
|
||||
osd_->ReloadSettings();
|
||||
collection_view_->ReloadSettings();
|
||||
app_->player()->engine()->ReloadSettings();
|
||||
ui_->playlist->view()->ReloadSettings();
|
||||
|
||||
}
|
||||
@@ -842,7 +840,7 @@ void MainWindow::resizeEvent(QResizeEvent*) { SaveGeometry(); }
|
||||
|
||||
void MainWindow::TabSwitched() {
|
||||
|
||||
if (ui_->tabs->current_index() > 0)
|
||||
if (ui_->tabs->currentIndex() > 0)
|
||||
ui_->now_playing->SetEnabled();
|
||||
else
|
||||
ui_->now_playing->SetDisabled();
|
||||
@@ -860,7 +858,7 @@ void MainWindow::SaveGeometry() {
|
||||
settings_.setValue("geometry", saveGeometry());
|
||||
}
|
||||
settings_.setValue("splitter_state", ui_->splitter->saveState());
|
||||
settings_.setValue("current_tab", ui_->tabs->current_index());
|
||||
settings_.setValue("current_tab", ui_->tabs->currentIndex());
|
||||
settings_.setValue("tab_mode", ui_->tabs->mode());
|
||||
|
||||
}
|
||||
@@ -896,9 +894,6 @@ void MainWindow::LoadPlaybackStatus() {
|
||||
saved_playback_state_ = static_cast<Engine::State> (settings.value("playback_state", Engine::Empty).toInt());
|
||||
saved_playback_position_ = settings.value("playback_position", 0).toDouble();
|
||||
settings.endGroup();
|
||||
|
||||
qLog(Debug) << "playback_state" << saved_playback_state_;
|
||||
qLog(Debug) << "playback_position" << saved_playback_position_;
|
||||
|
||||
if (saved_playback_state_ == Engine::Empty || saved_playback_state_ == Engine::Idle) {
|
||||
return;
|
||||
@@ -1699,7 +1694,7 @@ bool MainWindow::LoadUrl(const QString &url) {
|
||||
}
|
||||
|
||||
void MainWindow::CheckForUpdates() {
|
||||
#if defined(Q_OS_DARWIN)
|
||||
#if defined(Q_OS_MACOS)
|
||||
mac::CheckForUpdates();
|
||||
#endif
|
||||
}
|
||||
@@ -2232,7 +2227,7 @@ void MainWindow::HandleNotificationPreview(OSD::Behaviour type, QString line1, Q
|
||||
}
|
||||
|
||||
void MainWindow::FocusCollectionTab() {
|
||||
ui_->tabs->SetCurrentWidget(collection_view_);
|
||||
ui_->tabs->setCurrentWidget(collection_view_);
|
||||
}
|
||||
|
||||
void MainWindow::ShowConsole() {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
# include <gst/gstelement.h>
|
||||
#endif
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QAbstractSocket>
|
||||
#include <QMetaType>
|
||||
#include <QList>
|
||||
@@ -100,7 +101,6 @@ void RegisterMetaTypes() {
|
||||
qRegisterMetaTypeStreamOperators<Equalizer::Params>("Equalizer::Params");
|
||||
#ifdef HAVE_DBUS
|
||||
qDBusRegisterMetaType<QList<QByteArray>>();
|
||||
qDBusRegisterMetaType<QImage>();
|
||||
qDBusRegisterMetaType<TrackMetadata>();
|
||||
qDBusRegisterMetaType<TrackIds>();
|
||||
qDBusRegisterMetaType<MprisPlaylist>();
|
||||
@@ -108,7 +108,9 @@ void RegisterMetaTypes() {
|
||||
qDBusRegisterMetaType<MaybePlaylist>();
|
||||
qDBusRegisterMetaType<InterfacesAndProperties>();
|
||||
qDBusRegisterMetaType<ManagedObjectList>();
|
||||
#ifdef HAVE_X11
|
||||
qDBusRegisterMetaType<QImage>();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -75,120 +75,100 @@ using std::shared_ptr;
|
||||
Player::Player(Application *app, QObject *parent)
|
||||
: PlayerInterface(parent),
|
||||
app_(app),
|
||||
//engine_(new GstEngine(app_->task_manager())),
|
||||
//engine_(CreateEngine()),
|
||||
stream_change_type_(Engine::First),
|
||||
last_state_(Engine::Empty),
|
||||
nb_errors_received_(0),
|
||||
volume_before_mute_(50),
|
||||
last_pressed_previous_(QDateTime::currentDateTime()),
|
||||
menu_previousmode_(PreviousBehaviour_DontRestart),
|
||||
seek_step_sec_(10)
|
||||
{
|
||||
seek_step_sec_(10) {
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
Engine::EngineType enginetype = Engine::EngineTypeFromName(s.value("engine", BackendSettingsPage::EngineText_GStreamer).toString().toLower());
|
||||
Engine::EngineType enginetype = Engine::EngineTypeFromName(s.value("engine", EngineName(Engine::GStreamer)).toString().toLower());
|
||||
s.endGroup();
|
||||
|
||||
CreateEngine(enginetype);
|
||||
|
||||
settings_.beginGroup("Player");
|
||||
|
||||
SetVolume(settings_.value("volume", 100).toInt());
|
||||
|
||||
#if 0
|
||||
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
||||
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
||||
#endif
|
||||
int volume = settings_.value("volume", 50).toInt();
|
||||
SetVolume(volume);
|
||||
|
||||
}
|
||||
|
||||
Player::~Player() {}
|
||||
Player::~Player() {
|
||||
settings_.endGroup();
|
||||
}
|
||||
|
||||
EngineBase *Player::CreateEngine(Engine::EngineType enginetype) {
|
||||
|
||||
bool engine = false;
|
||||
EngineBase *enginebase = nullptr;
|
||||
void Player::CreateEngine(Engine::EngineType enginetype) {
|
||||
|
||||
for (int i = 1 ; !engine ; i++) {
|
||||
Engine::EngineType use_enginetype = Engine::None;
|
||||
|
||||
for (int i = 0 ; use_enginetype == Engine::None ; i++) {
|
||||
switch(enginetype) {
|
||||
case Engine::None:
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case Engine::GStreamer:
|
||||
engine=true;
|
||||
enginetype=Engine::GStreamer;
|
||||
enginebase = new GstEngine(app_->task_manager());
|
||||
use_enginetype=Engine::GStreamer;
|
||||
engine_.reset(new GstEngine(app_->task_manager()));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
case Engine::Xine:
|
||||
engine=true;
|
||||
enginetype=Engine::Xine;
|
||||
enginebase = new XineEngine(app_->task_manager());
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_PHONON
|
||||
case Engine::Phonon:
|
||||
engine=true;
|
||||
enginetype=Engine::Phonon;
|
||||
enginebase = new PhononEngine(app_->task_manager());
|
||||
use_enginetype=Engine::Xine;
|
||||
engine_.reset(new XineEngine(app_->task_manager()));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_VLC
|
||||
case Engine::VLC:
|
||||
engine=true;
|
||||
enginetype=Engine::VLC;
|
||||
enginebase = new VLCEngine(app_->task_manager());
|
||||
use_enginetype=Engine::VLC;
|
||||
engine_.reset(new VLCEngine(app_->task_manager()));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_PHONON
|
||||
case Engine::Phonon:
|
||||
use_enginetype=Engine::Phonon;
|
||||
engine_.reset(new PhononEngine(app_->task_manager()));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
if (i > 1) { qFatal("No engine available!"); return nullptr; }
|
||||
QSettings s;
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
s.setValue("engine", "");
|
||||
s.setValue("output", "");
|
||||
s.setValue("device", "");
|
||||
s.endGroup();
|
||||
enginetype = Engine::None;
|
||||
break;
|
||||
if (i > 0) { qFatal("No engine available!"); }
|
||||
enginetype = Engine::None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
s.setValue("engine", Engine::EngineNameFromType(enginetype));
|
||||
s.endGroup();
|
||||
|
||||
if (enginebase == nullptr) {
|
||||
qFatal("Failed to create engine!");
|
||||
return nullptr;
|
||||
if (use_enginetype != enginetype) { // Engine was set to something else. Reset output and device.
|
||||
QSettings s;
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
s.setValue("engine", EngineName(use_enginetype));
|
||||
s.setValue("output", engine_->DefaultOutput());
|
||||
s.setValue("device", QVariant(""));
|
||||
s.endGroup();
|
||||
}
|
||||
|
||||
engine_.reset(enginebase);
|
||||
|
||||
return enginebase;
|
||||
if (!engine_) {
|
||||
qFatal("Failed to create engine!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Player::Init() {
|
||||
|
||||
if (!engine_->Init()) { qFatal("Error initialising audio engine"); }
|
||||
|
||||
analyzer_->SetEngine(engine_.get());
|
||||
|
||||
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
||||
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
||||
|
||||
if (!engine_->Init()) qFatal("Error initialising audio engine");
|
||||
|
||||
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
|
||||
connect(engine_.get(), SIGNAL(TrackAboutToEnd()), SLOT(TrackAboutToEnd()));
|
||||
connect(engine_.get(), SIGNAL(TrackEnded()), SLOT(TrackEnded()));
|
||||
connect(engine_.get(), SIGNAL(MetaData(Engine::SimpleMetaBundle)), SLOT(EngineMetadataReceived(Engine::SimpleMetaBundle)));
|
||||
|
||||
engine_->SetVolume(settings_.value("volume", 50).toInt());
|
||||
|
||||
analyzer_->SetEngine(engine_.get());
|
||||
int volume = settings_.value("volume", 50).toInt();
|
||||
engine_->SetVolume(volume);
|
||||
|
||||
// Equalizer
|
||||
qLog(Debug) << "Creating equalizer";
|
||||
@@ -197,7 +177,6 @@ void Player::Init() {
|
||||
connect(equalizer_, SIGNAL(StereoBalanceChanged(float)), app_->player()->engine(), SLOT(SetStereoBalance(float)));
|
||||
|
||||
engine_->SetEqualizerEnabled(equalizer_->is_enabled());
|
||||
|
||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||
engine_->SetStereoBalance(equalizer_->stereo_balance());
|
||||
|
||||
@@ -205,15 +184,6 @@ void Player::Init() {
|
||||
|
||||
}
|
||||
|
||||
void Player::SetAnalyzer(AnalyzerContainer *analyzer) {
|
||||
|
||||
analyzer_ = analyzer;
|
||||
|
||||
}
|
||||
void Player::SetEqualizer(Equalizer *equalizer) {
|
||||
equalizer_ = equalizer;
|
||||
}
|
||||
|
||||
void Player::ReloadSettings() {
|
||||
|
||||
QSettings s;
|
||||
|
||||
@@ -129,7 +129,7 @@ class Player : public PlayerInterface {
|
||||
PreviousBehaviour_Restart = 2
|
||||
};
|
||||
|
||||
EngineBase *CreateEngine(Engine::EngineType enginetype);
|
||||
void CreateEngine(Engine::EngineType enginetype);
|
||||
void Init();
|
||||
|
||||
EngineBase *engine() const { return engine_.get(); }
|
||||
@@ -145,9 +145,9 @@ class Player : public PlayerInterface {
|
||||
const UrlHandler *HandlerForUrl(const QUrl &url) const;
|
||||
|
||||
bool PreviousWouldRestartTrack() const;
|
||||
|
||||
void SetAnalyzer(AnalyzerContainer *analyzer);
|
||||
void SetEqualizer(Equalizer *equalizer);
|
||||
|
||||
void SetAnalyzer(AnalyzerContainer *analyzer) { analyzer_ = analyzer; }
|
||||
void SetEqualizer(Equalizer *equalizer) { equalizer_ = equalizer; }
|
||||
|
||||
public slots:
|
||||
void ReloadSettings();
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "screensaver.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
#include "macscreensaver.h"
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,7 @@ Screensaver *Screensaver::GetScreensaver() {
|
||||
else if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kKdeService)) {
|
||||
screensaver_ = new DBusScreensaver(kKdeService, kKdePath, kKdeInterface);
|
||||
}
|
||||
#elif defined(Q_OS_DARWIN)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
screensaver_ = new MacScreensaver();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -365,9 +365,9 @@ QString Song::TextForFiletype(FileType type) {
|
||||
|
||||
switch (type) {
|
||||
case Song::Type_Wav: return QObject::tr("Wav");
|
||||
case Song::Type_Flac: return QObject::tr("Flac");
|
||||
case Song::Type_Flac: return QObject::tr("FLAC");
|
||||
case Song::Type_WavPack: return QObject::tr("WavPack");
|
||||
case Song::Type_OggFlac: return QObject::tr("Ogg Flac");
|
||||
case Song::Type_OggFlac: return QObject::tr("Ogg FLAC");
|
||||
case Song::Type_OggVorbis: return QObject::tr("Ogg Vorbis");
|
||||
case Song::Type_OggOpus: return QObject::tr("Ogg Opus");
|
||||
case Song::Type_OggSpeex: return QObject::tr("Ogg Speex");
|
||||
|
||||
@@ -87,7 +87,7 @@ void StyleSheetLoader::UpdateStyleSheet(QWidget *widget) {
|
||||
ReplaceColor(&contents, "Link", p, QPalette::Link);
|
||||
ReplaceColor(&contents, "LinkVisited", p, QPalette::LinkVisited);
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
contents.replace("darwin", "*");
|
||||
#endif
|
||||
|
||||
|
||||
@@ -30,8 +30,11 @@
|
||||
#include <QRect>
|
||||
#include <QVector>
|
||||
|
||||
#include "qtsystemtrayicon.h"
|
||||
#include "systemtrayicon.h"
|
||||
#include "qtsystemtrayicon.h"
|
||||
#ifdef Q_OS_MACOS
|
||||
# include "macsystemtrayicon.h"
|
||||
#endif
|
||||
|
||||
SystemTrayIcon::SystemTrayIcon(QObject *parent)
|
||||
: QObject(parent),
|
||||
@@ -103,7 +106,7 @@ void SystemTrayIcon::SetStopped() {
|
||||
}
|
||||
|
||||
SystemTrayIcon* SystemTrayIcon::CreateSystemTrayIcon(QObject *parent) {
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
return new MacSystemTrayIcon(parent);
|
||||
#else
|
||||
return new QtSystemTrayIcon(parent);
|
||||
|
||||
@@ -59,26 +59,27 @@
|
||||
#include <QtDebug>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <sys/resource.h>
|
||||
#ifdef Q_OS_MACOS
|
||||
# include <sys/resource.h>
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <sys/statvfs.h>
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#include <windows.h>
|
||||
# include <sys/statvfs.h>
|
||||
#elif defined(Q_OS_WIN)
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <QProcess>
|
||||
|
||||
#include "CoreServices/CoreServices.h"
|
||||
#include "IOKit/ps/IOPSKeys.h"
|
||||
#include "IOKit/ps/IOPowerSources.h"
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#ifdef Q_OS_MACOS
|
||||
# include <QProcess>
|
||||
# include "CoreServices/CoreServices.h"
|
||||
# include "IOKit/ps/IOPSKeys.h"
|
||||
# include "IOKit/ps/IOPowerSources.h"
|
||||
#elif defined(Q_OS_WIN)
|
||||
#include <QProcess>
|
||||
#endif
|
||||
|
||||
@@ -89,10 +90,10 @@
|
||||
#include "timeconstants.h"
|
||||
#include "application.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "mac_startup.h"
|
||||
#include "mac_utilities.h"
|
||||
#include "scoped_cftyperef.h"
|
||||
#ifdef Q_OS_MACOS
|
||||
# include "mac_startup.h"
|
||||
# include "mac_utilities.h"
|
||||
# include "scoped_cftyperef.h"
|
||||
#endif
|
||||
|
||||
namespace Utilities {
|
||||
@@ -361,7 +362,7 @@ QString ColorToRgba(const QColor &c) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
qint32 GetMacVersion() {
|
||||
|
||||
SInt32 minor_version;
|
||||
@@ -374,7 +375,7 @@ qint32 GetMacVersion() {
|
||||
void RevealFileInFinder(QString const &path) {
|
||||
QProcess::execute("/usr/bin/open", QStringList() << "-R" << path);
|
||||
}
|
||||
#endif // Q_OS_DARWIN
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void ShowFileInExplorer(QString const &path) {
|
||||
@@ -398,7 +399,7 @@ void OpenInFileBrowser(const QList<QUrl> &urls) {
|
||||
if (dirs.contains(directory)) continue;
|
||||
dirs.insert(directory);
|
||||
qLog(Debug) << path;
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
// Revealing multiple files in the finder only opens one window, so it also makes sense to reveal at most one per directory
|
||||
RevealFileInFinder(path);
|
||||
#elif defined(Q_OS_WIN32)
|
||||
@@ -642,7 +643,7 @@ int SetThreadIOPriority(IoPriority priority) {
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
return syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, GetThreadId(), 4 | priority << IOPRIO_CLASS_SHIFT);
|
||||
#elif defined(Q_OS_DARWIN)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return setpriority(PRIO_DARWIN_THREAD, 0, priority == IOPRIO_CLASS_IDLE ? PRIO_DARWIN_BG : 0);
|
||||
#else
|
||||
return 0;
|
||||
@@ -671,7 +672,7 @@ bool IsLaptop() {
|
||||
return !(status.BatteryFlag & 128); // 128 = no system battery
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return !QDir("/proc/acpi/battery").entryList(QDir::Dirs | QDir::NoDotAndDotDot).isEmpty();
|
||||
#elif defined(Q_OS_MAC)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
ScopedCFTypeRef<CFTypeRef> power_sources(IOPSCopyPowerSourcesInfo());
|
||||
ScopedCFTypeRef<CFArrayRef> power_source_list(IOPSCopyPowerSourcesList(power_sources.get()));
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(power_source_list.get()); ++i) {
|
||||
@@ -752,7 +753,7 @@ void SetEnv(const char *key, const QString &value) {
|
||||
|
||||
void IncreaseFDLimit() {
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#ifdef Q_OS_MACOS
|
||||
// Bump the soft limit for the number of file descriptors from the default of 256 to the maximum (usually 10240).
|
||||
struct rlimit limit;
|
||||
getrlimit(RLIMIT_NOFILE, &limit);
|
||||
|
||||