mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-01 01:51:58 +02:00
Merge branch 'master' into jreen-tpqt4-comp
Conflicts: CMakeLists.txt src/tomahawkapp.cpp
This commit is contained in:
@@ -7,7 +7,7 @@ CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
|
||||
SET( TOMAHAWK_ORGANIZATION_NAME "Tomahawk" )
|
||||
SET( TOMAHAWK_ORGANIZATION_DOMAIN "tomahawk-player.org" )
|
||||
SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" )
|
||||
SET( TOMAHAWK_VERSION "0.0.2" )
|
||||
SET( TOMAHAWK_VERSION "0.0.3" )
|
||||
|
||||
|
||||
# set paths
|
||||
|
20
ChangeLog
20
ChangeLog
@@ -1,7 +1,25 @@
|
||||
Version 0.1.0:
|
||||
* Watch folders for changes and automatically update your collection. This
|
||||
is on by default; you can turn it off on the Local Music tab in the
|
||||
settings dialog. Note that this triggers only on files or folders being
|
||||
added to or removed from folders; it is not watch individual files as
|
||||
most OSes can't support enough file watches to handle a normal-sized
|
||||
music collection.
|
||||
|
||||
Version 0.0.3:
|
||||
* Fix crashes in Twitter authentication. For reals now.
|
||||
* Fixed an issue which caused duplicate items when rescanning.
|
||||
* Revert change introduced in 0.0.2 causing Twitter protocol to not try
|
||||
to reconnect to a peer if it couldn't connect the first time the plugin
|
||||
was connected. This caused confusing (and for most unwanted) behavior.
|
||||
* Fix crashes in Twitter authentication.
|
||||
* Properly honor the chosen port number if a static host and port are
|
||||
marked as preferred.
|
||||
* Don't automatically try to resolve all incoming playback logs. This
|
||||
speeds up importing sources a lot.
|
||||
* Faster painting of playlists with lots of unresolved tracks.
|
||||
* The tomahawk:// protocol handler works on Windows now.
|
||||
* Fixed launching Tomahawk from Windows installer with admin privileges.
|
||||
* Prefer local results when results' score is equal.
|
||||
|
||||
Version 0.0.2:
|
||||
* Don't reconnect to Jabber if the settings dialog is closed successfully
|
||||
|
0
admin/win/nsi/RELEASE_NOTES.txt
Executable file → Normal file
0
admin/win/nsi/RELEASE_NOTES.txt
Executable file → Normal file
0
admin/win/nsi/installer.ico
Executable file → Normal file
0
admin/win/nsi/installer.ico
Executable file → Normal file
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
admin/win/nsi/nsis_processes/bin/Processes.dll
Executable file
BIN
admin/win/nsi/nsis_processes/bin/Processes.dll
Executable file
Binary file not shown.
35
admin/win/nsi/nsis_processes/license.rtf
Executable file
35
admin/win/nsi/nsis_processes/license.rtf
Executable file
@@ -0,0 +1,35 @@
|
||||
{\rtf1\ansi\ansicpg1252\uc1\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Verdana;}
|
||||
{\f172\froman\fcharset238\fprq2 Times New Roman CE;}{\f173\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f175\froman\fcharset161\fprq2 Times New Roman Greek;}{\f176\froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\f177\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f178\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f179\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f180\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\f562\fswiss\fcharset238\fprq2 Verdana CE;}{\f563\fswiss\fcharset204\fprq2 Verdana Cyr;}{\f565\fswiss\fcharset161\fprq2 Verdana Greek;}{\f566\fswiss\fcharset162\fprq2 Verdana Tur;}{\f569\fswiss\fcharset186\fprq2 Verdana Baltic;}
|
||||
{\f570\fswiss\fcharset163\fprq2 Verdana (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;
|
||||
\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{
|
||||
\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\*
|
||||
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv
|
||||
\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}{\*\cs15 \additive \ul\cf2 \sbasedon10 \styrsid7485074 Hyperlink;}}
|
||||
{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\rsidtbl \rsid6712196\rsid7485074\rsid11352300\rsid15940516}{\*\generator Microsoft Word 11.0.5604;}{\info{\title Processes v1}{\author Hardwired}{\operator Hardwired}{\creatim\yr2004\mo12\dy12\hr23\min42}
|
||||
{\revtim\yr2004\mo12\dy12\hr23\min51}{\version2}{\edmins9}{\nofpages1}{\nofwords80}{\nofchars458}{\nofcharsws537}{\vern24689}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180
|
||||
\dgvspace180\dghorigin1800\dgvorigin1440\dghshow1\dgvshow1
|
||||
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
|
||||
\asianbrkrule\rsidroot7485074\newtblstyruls\nogrowautofit \fet0\sectd \linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}
|
||||
{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}
|
||||
{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain
|
||||
\qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7485074 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\b\f39\insrsid7485074\charrsid7485074 Processes v1.0}{\f39\insrsid7485074\charrsid7485074 .0.1
|
||||
\par }{\f39\fs20\insrsid7485074
|
||||
\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15940516 {\f39\fs20\insrsid15940516 This software binaries and source-code are free for any kind of use, including commercial use. }{
|
||||
\f39\fs20\insrsid7485074\charrsid7485074 There is no restriction and no guaranty for using}{\f39\fs20\insrsid7485074\charrsid7485074 t}{\f39\fs20\insrsid7485074\charrsid7485074 his software}{\f39\fs20\insrsid7485074\charrsid7485074 and/or it
|
||||
s source-code. }{\f39\fs20\insrsid15940516
|
||||
\par I}{\f39\fs20\insrsid7485074\charrsid7485074 f you use the plug}{\f39\fs20\insrsid7485074\charrsid7485074 -}{\f39\fs20\insrsid7485074\charrsid7485074 in }{\f39\fs20\insrsid7485074\charrsid7485074 and/}{\f39\fs20\insrsid7485074\charrsid7485074 or it}{
|
||||
\f39\fs20\insrsid7485074\charrsid7485074 s}{\f39\fs20\insrsid7485074\charrsid7485074 source-code, I would }{\f39\fs20\insrsid7485074\charrsid7485074 appreciate }{\f39\fs20\insrsid7485074\charrsid7485074 if my name is mentioned.}{
|
||||
\f39\fs20\insrsid7485074\charrsid7485074
|
||||
\par }\pard \qj \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7485074 {\f39\fs20\insrsid7485074\charrsid7485074
|
||||
\par }{\b\f39\fs20\insrsid7485074\charrsid7485074 Andrei Ciubotaru [Hardwired]
|
||||
\par }{\f39\fs20\insrsid7485074\charrsid7485074 Lead Developer ICode&Ideas SRL (}{\field\flddirty{\*\fldinst {\f39\fs20\insrsid7485074\charrsid7485074 HYPERLINK "http://www.icode.ro/" }{\f39\fs20\insrsid7485074\charrsid7485074 {\*\datafield
|
||||
00d0c9ea79f9bace118c8200aa004ba90b02000000170000001500000068007400740070003a002f002f007700770077002e00690063006f00640065002e0072006f002f000000e0c9ea79f9bace118c8200aa004ba90b2a00000068007400740070003a002f002f007700770077002e00690063006f00640065002e007200
|
||||
6f002f000000}}}{\fldrslt {\cs15\f39\fs20\ul\cf2\insrsid7485074\charrsid7485074 http://www.icode.ro/}}}{\f39\fs20\insrsid7485074\charrsid7485074 )
|
||||
\par }{\field{\*\fldinst {\f39\fs20\insrsid7485074 HYPERLINK "hardwiredteks@gmail.com" }{\f39\fs20\insrsid15940516\charrsid7485074 {\*\datafield
|
||||
00d0c9ea79f9bace118c8200aa004ba90b02000000010000000303000000000000c00000000000004600001800000068617264776972656474656b7340676d61696c2e636f6d00ffffadde000000000000000000000000000000000000000000000000}}}{\fldrslt {
|
||||
\cs15\f39\fs20\ul\cf2\insrsid7485074\charrsid7485074 hardwiredteks@gmail.com}}}{\f39\fs20\insrsid7485074\charrsid7485074 , }{\field{\*\fldinst {\f39\fs20\insrsid7485074 HYPERLINK "hardwired@icode.ro" }{\f39\fs20\insrsid15940516\charrsid7485074
|
||||
{\*\datafield 00d0c9ea79f9bace118c8200aa004ba90b02000000010000000303000000000000c0000000000000460000130000006861726477697265644069636f64652e726f00ffffadde000000000000000000000000000000000000000000000000}}}{\fldrslt {
|
||||
\cs15\f39\fs20\ul\cf2\insrsid7485074\charrsid7485074 hardwired@icode.ro}}}{\f39\fs20\insrsid7485074\charrsid7485074
|
||||
\par }}
|
122
admin/win/nsi/nsis_processes/readme.txt
Executable file
122
admin/win/nsi/nsis_processes/readme.txt
Executable file
@@ -0,0 +1,122 @@
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
||||
Processes (Processes.dll)
|
||||
Version: 1.0.1.0
|
||||
Release: 24.february.2005
|
||||
Description: Nullsoft Installer (NSIS) plug-in for managing?!
|
||||
Windows processes.
|
||||
|
||||
Copyright: <09> 2004-2005 Hardwired. No rights reserved.
|
||||
There is no restriction and no guaranty for using
|
||||
this software.
|
||||
|
||||
Author: Andrei Ciubotaru [Hardwired]
|
||||
Lead Developer ICode&Ideas SRL (http://www.icode.ro/)
|
||||
hardwiredteks@gmail.com, hardwired@icode.ro
|
||||
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
||||
INTRODUCTION
|
||||
|
||||
The Need For Plug-in - I need it for the one of my installers.
|
||||
|
||||
Briefly: Use it when you need to find\kill a process when
|
||||
installing\uninstalling some application. Also, use it when you
|
||||
need to test the presence of a device driver.
|
||||
|
||||
|
||||
SUPPORT
|
||||
|
||||
Supported platforms are: WinNT,Win2K,WinXP and Win2003 Server.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Processes::FindProcess <process_name> ;without ".exe"
|
||||
|
||||
Searches the currently running processes for the given
|
||||
process name.
|
||||
|
||||
return: 1 - the process was found
|
||||
0 - the process was not found
|
||||
|
||||
Processes::KillProcess <process_name> ; without ".exe"
|
||||
|
||||
Searches the currently running processes for the given
|
||||
process name. If the process is found then the it gets
|
||||
killed.
|
||||
|
||||
return: 1 - the process was found and killed
|
||||
0 - the process was not found or the process
|
||||
cannot be killed (insuficient rights)
|
||||
|
||||
Processes::FindDevice <device_base_name>
|
||||
|
||||
Searches the installed devices drivers for the given
|
||||
device base name.
|
||||
(important: I said BASE NAME not FILENAME)
|
||||
|
||||
return: 1 - the device driver was found
|
||||
0 - the device driver was not found
|
||||
|
||||
|
||||
USAGE
|
||||
|
||||
First of all, does not matter where you use it. Ofcourse, the
|
||||
routines must be called inside of a Section/Function scope.
|
||||
|
||||
Processes::FindProcess "process_name"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" make_my_day noooooo
|
||||
|
||||
make_my_day:
|
||||
...
|
||||
|
||||
noooooo:
|
||||
...
|
||||
|
||||
|
||||
Processes::KillProcess "process_name"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" dead_meat why_wont_you_die
|
||||
|
||||
dead_meat:
|
||||
...
|
||||
|
||||
why_wont_you_die:
|
||||
...
|
||||
|
||||
|
||||
Processes::FindDevice "device_base_name"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" blabla more_blabla
|
||||
|
||||
blabla:
|
||||
...
|
||||
|
||||
more_blabla:
|
||||
...
|
||||
|
||||
|
||||
THANKS
|
||||
|
||||
Sunil Kamath for inspiring me. I wanted to use its FindProcDLL
|
||||
but my requirements made it imposible.
|
||||
|
||||
Nullsoft for creating this very powerfull installer. One big,
|
||||
free and full-featured (hmmm... and guiless for the moment) mean
|
||||
install machine!:)
|
||||
|
||||
ME for being such a great coder...
|
||||
... HAHAHAHAHAHAHA!
|
||||
|
||||
ONE MORE THING
|
||||
|
||||
If you use the plugin or it's source-code, I would apreciate
|
||||
if my name is mentioned.
|
||||
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
8
admin/win/nsi/nsis_processes/src/StdAfx.cpp
Executable file
8
admin/win/nsi/nsis_processes/src/StdAfx.cpp
Executable file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// KillProcDLL.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
34
admin/win/nsi/nsis_processes/src/StdAfx.h
Executable file
34
admin/win/nsi/nsis_processes/src/StdAfx.h
Executable file
@@ -0,0 +1,34 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__780690DC_E128_403D_BC07_780D1B2CC101__INCLUDED_)
|
||||
#define AFX_STDAFX_H__780690DC_E128_403D_BC07_780D1B2CC101__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string> // String management...
|
||||
|
||||
//From exam28.cpp
|
||||
#include <tlhelp32.h>
|
||||
//#include <iostream.h>
|
||||
|
||||
#ifdef BORLANDC
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
//To make it a NSIS Plug-In
|
||||
#include "exdll.h"
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__780690DC_E128_403D_BC07_780D1B2CC101__INCLUDED_)
|
37
admin/win/nsi/nsis_processes/src/exdll.c
Executable file
37
admin/win/nsi/nsis_processes/src/exdll.c
Executable file
@@ -0,0 +1,37 @@
|
||||
#include <windows.h>
|
||||
#include "exdll.h"
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
|
||||
HWND g_hwndParent;
|
||||
|
||||
void __declspec(dllexport) myFunction(HWND hwndParent, int string_size,
|
||||
char *variables, stack_t **stacktop)
|
||||
{
|
||||
g_hwndParent=hwndParent;
|
||||
|
||||
EXDLL_INIT();
|
||||
|
||||
|
||||
// note if you want parameters from the stack, pop them off in order.
|
||||
// i.e. if you are called via exdll::myFunction file.dat poop.dat
|
||||
// calling popstring() the first time would give you file.dat,
|
||||
// and the second time would give you poop.dat.
|
||||
// you should empty the stack of your parameters, and ONLY your
|
||||
// parameters.
|
||||
|
||||
// do your stuff here
|
||||
{
|
||||
char buf[1024];
|
||||
wsprintf(buf,"$0=%s\n",getuservariable(INST_0));
|
||||
MessageBox(g_hwndParent,buf,0,MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
g_hInstance=hInst;
|
||||
return TRUE;
|
||||
}
|
136
admin/win/nsi/nsis_processes/src/exdll.h
Executable file
136
admin/win/nsi/nsis_processes/src/exdll.h
Executable file
@@ -0,0 +1,136 @@
|
||||
#ifndef _EXDLL_H_
|
||||
#define _EXDLL_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// only include this file from one place in your DLL.
|
||||
// (it is all static, if you use it in two places it will fail)
|
||||
//
|
||||
#define EXDLL_INIT() { \
|
||||
g_stringsize = string_size; \
|
||||
g_stacktop = stacktop; \
|
||||
g_variables = variables; }
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// For page showing plug-ins
|
||||
//
|
||||
#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8)
|
||||
#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd)
|
||||
#define NOTIFY_BYE_BYE 'x'
|
||||
|
||||
typedef struct _stack_t
|
||||
{
|
||||
struct _stack_t *next;
|
||||
char text[1]; // this should be the length of string_size
|
||||
} stack_t;
|
||||
|
||||
|
||||
static unsigned int g_stringsize;
|
||||
static stack_t **g_stacktop;
|
||||
static char *g_variables;
|
||||
|
||||
enum
|
||||
{
|
||||
INST_0, // $0
|
||||
INST_1, // $1
|
||||
INST_2, // $2
|
||||
INST_3, // $3
|
||||
INST_4, // $4
|
||||
INST_5, // $5
|
||||
INST_6, // $6
|
||||
INST_7, // $7
|
||||
INST_8, // $8
|
||||
INST_9, // $9
|
||||
INST_R0, // $R0
|
||||
INST_R1, // $R1
|
||||
INST_R2, // $R2
|
||||
INST_R3, // $R3
|
||||
INST_R4, // $R4
|
||||
INST_R5, // $R5
|
||||
INST_R6, // $R6
|
||||
INST_R7, // $R7
|
||||
INST_R8, // $R8
|
||||
INST_R9, // $R9
|
||||
INST_CMDLINE, // $CMDLINE
|
||||
INST_INSTDIR, // $INSTDIR
|
||||
INST_OUTDIR, // $OUTDIR
|
||||
INST_EXEDIR, // $EXEDIR
|
||||
INST_LANG, // $LANGUAGE
|
||||
__INST_LAST
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// utility functions (not required but often useful)
|
||||
//
|
||||
static int popstring( char *str )
|
||||
{
|
||||
stack_t *th;
|
||||
|
||||
|
||||
if( !g_stacktop ||
|
||||
!*g_stacktop )
|
||||
return 1;
|
||||
|
||||
th = (*g_stacktop);
|
||||
lstrcpy( str, th->text );
|
||||
*g_stacktop = th->next;
|
||||
GlobalFree( (HGLOBAL)th );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void pushstring( char *str )
|
||||
{
|
||||
stack_t *th;
|
||||
|
||||
|
||||
if( !g_stacktop )
|
||||
return;
|
||||
|
||||
th = (stack_t*)GlobalAlloc( GPTR, sizeof(stack_t) + g_stringsize );
|
||||
lstrcpyn( th->text, str, g_stringsize );
|
||||
th->next = *g_stacktop;
|
||||
*g_stacktop = th;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static char *getuservariable( int varnum )
|
||||
{
|
||||
if( varnum < 0 ||
|
||||
varnum >= __INST_LAST )
|
||||
return NULL;
|
||||
|
||||
return (g_variables + varnum*g_stringsize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void setuservariable( int varnum, char *var )
|
||||
{
|
||||
if( var != NULL &&
|
||||
varnum >= 0 &&
|
||||
varnum < __INST_LAST )
|
||||
lstrcpy( g_variables + varnum*g_stringsize, var );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif//_EXDLL_H_
|
411
admin/win/nsi/nsis_processes/src/processes.cpp
Executable file
411
admin/win/nsi/nsis_processes/src/processes.cpp
Executable file
@@ -0,0 +1,411 @@
|
||||
#include "stdafx.h"
|
||||
#include "processes.h"
|
||||
#include "string.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// global variables
|
||||
lpfEnumProcesses EnumProcesses;
|
||||
lpfEnumProcessModules EnumProcessModules;
|
||||
lpfGetModuleBaseName GetModuleBaseName;
|
||||
lpfEnumDeviceDrivers EnumDeviceDrivers;
|
||||
lpfGetDeviceDriverBaseName GetDeviceDriverBaseName;
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
HWND g_hwndParent;
|
||||
HINSTANCE g_hInstLib;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// main DLL entry
|
||||
BOOL WINAPI _DllMainCRTStartup( HANDLE hInst,
|
||||
ULONG ul_reason_for_call,
|
||||
LPVOID lpReserved )
|
||||
{
|
||||
g_hInstance = (struct HINSTANCE__ *)hInst;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// loads the psapi routines
|
||||
bool LoadPSAPIRoutines( void )
|
||||
{
|
||||
if( NULL == (g_hInstLib = LoadLibraryA( "PSAPI.DLL" )) )
|
||||
return false;
|
||||
|
||||
EnumProcesses = (lpfEnumProcesses) GetProcAddress( g_hInstLib, "EnumProcesses" );
|
||||
EnumProcessModules = (lpfEnumProcessModules) GetProcAddress( g_hInstLib, "EnumProcessModules" );
|
||||
GetModuleBaseName = (lpfGetModuleBaseName) GetProcAddress( g_hInstLib, "GetModuleBaseNameA" );
|
||||
EnumDeviceDrivers = (lpfEnumDeviceDrivers) GetProcAddress( g_hInstLib, "EnumDeviceDrivers" );
|
||||
GetDeviceDriverBaseName = (lpfGetDeviceDriverBaseName) GetProcAddress( g_hInstLib, "GetDeviceDriverBaseNameA" );
|
||||
|
||||
if( ( NULL == EnumProcesses ) ||
|
||||
( NULL == EnumProcessModules ) ||
|
||||
( NULL == EnumDeviceDrivers ) ||
|
||||
( NULL == GetModuleBaseName ) ||
|
||||
( NULL == GetDeviceDriverBaseName ) )
|
||||
{
|
||||
FreeLibrary( g_hInstLib );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// free the psapi routines
|
||||
bool FreePSAPIRoutines( void )
|
||||
{
|
||||
EnumProcesses = NULL;
|
||||
EnumProcessModules = NULL;
|
||||
GetModuleBaseName = NULL;
|
||||
EnumDeviceDrivers = NULL;
|
||||
|
||||
if( FALSE == FreeLibrary( g_hInstLib ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// find a process by name
|
||||
// return value: true - process was found
|
||||
// false - process not found
|
||||
bool FindProc( char *szProcess )
|
||||
{
|
||||
char szProcessName[ 1024 ];
|
||||
char szCurrentProcessName[ 1024 ];
|
||||
DWORD dPID[ 1024 ];
|
||||
DWORD dPIDSize( 1024 );
|
||||
DWORD dSize( 1024 );
|
||||
HANDLE hProcess;
|
||||
HMODULE phModule[ 1024 ];
|
||||
|
||||
|
||||
//
|
||||
// make the name lower case
|
||||
//
|
||||
memset( szProcessName, 0, 1024*sizeof(char) );
|
||||
sprintf( szProcessName, "%s", szProcess );
|
||||
strlwr( szProcessName );
|
||||
|
||||
//
|
||||
// load PSAPI routines
|
||||
//
|
||||
if( false == LoadPSAPIRoutines() )
|
||||
return false;
|
||||
|
||||
//
|
||||
// enumerate processes names
|
||||
//
|
||||
if( FALSE == EnumProcesses( dPID, dSize, &dPIDSize ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// walk trough and compare see if the process is running
|
||||
//
|
||||
for( int k( dPIDSize / sizeof( DWORD ) ); k >= 0; k-- )
|
||||
{
|
||||
memset( szCurrentProcessName, 0, 1024*sizeof(char) );
|
||||
|
||||
if( NULL != ( hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dPID[ k ] ) ) )
|
||||
{
|
||||
if( TRUE == EnumProcessModules( hProcess, phModule, sizeof(HMODULE)*1024, &dPIDSize ) )
|
||||
if( GetModuleBaseName( hProcess, phModule[ 0 ], szCurrentProcessName, 1024 ) > 0 )
|
||||
{
|
||||
strlwr( szCurrentProcessName );
|
||||
|
||||
if( NULL != strstr( szCurrentProcessName, szProcessName ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
CloseHandle( hProcess );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle( hProcess );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// free PSAPI routines
|
||||
//
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// kills a process by name
|
||||
// return value: true - process was found
|
||||
// false - process not found
|
||||
bool KillProc( char *szProcess )
|
||||
{
|
||||
char szProcessName[ 1024 ];
|
||||
char szCurrentProcessName[ 1024 ];
|
||||
DWORD dPID[ 1024 ];
|
||||
DWORD dPIDSize( 1024 );
|
||||
DWORD dSize( 1024 );
|
||||
HANDLE hProcess;
|
||||
HMODULE phModule[ 1024 ];
|
||||
|
||||
|
||||
//
|
||||
// make the name lower case
|
||||
//
|
||||
memset( szProcessName, 0, 1024*sizeof(char) );
|
||||
sprintf( szProcessName, "%s", szProcess );
|
||||
strlwr( szProcessName );
|
||||
|
||||
//
|
||||
// load PSAPI routines
|
||||
//
|
||||
if( false == LoadPSAPIRoutines() )
|
||||
return false;
|
||||
|
||||
//
|
||||
// enumerate processes names
|
||||
//
|
||||
if( FALSE == EnumProcesses( dPID, dSize, &dPIDSize ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// walk trough and compare see if the process is running
|
||||
//
|
||||
for( int k( dPIDSize / sizeof( DWORD ) ); k >= 0; k-- )
|
||||
{
|
||||
memset( szCurrentProcessName, 0, 1024*sizeof(char) );
|
||||
|
||||
if( NULL != ( hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dPID[ k ] ) ) )
|
||||
{
|
||||
if( TRUE == EnumProcessModules( hProcess, phModule, sizeof(HMODULE)*1024, &dPIDSize ) )
|
||||
if( GetModuleBaseName( hProcess, phModule[ 0 ], szCurrentProcessName, 1024 ) > 0 )
|
||||
{
|
||||
strlwr( szCurrentProcessName );
|
||||
|
||||
if( NULL != strstr( szCurrentProcessName, szProcessName ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
|
||||
//
|
||||
// kill process
|
||||
//
|
||||
if( false == TerminateProcess( hProcess, 0 ) )
|
||||
{
|
||||
CloseHandle( hProcess );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// refresh systray
|
||||
//
|
||||
UpdateWindow( FindWindow( NULL, "Shell_TrayWnd" ) );
|
||||
|
||||
//
|
||||
// refresh desktop window
|
||||
//
|
||||
UpdateWindow( GetDesktopWindow() );
|
||||
|
||||
CloseHandle( hProcess );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle( hProcess );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// free PSAPI routines
|
||||
//
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
bool FindDev( char *szDriverName )
|
||||
{
|
||||
char szDeviceName[ 1024 ];
|
||||
char szCurrentDeviceName[ 1024 ];
|
||||
LPVOID lpDevices[ 1024 ];
|
||||
DWORD dDevicesSize( 1024 );
|
||||
DWORD dSize( 1024 );
|
||||
TCHAR tszCurrentDeviceName[ 1024 ];
|
||||
DWORD dNameSize( 1024 );
|
||||
|
||||
|
||||
//
|
||||
// make the name lower case
|
||||
//
|
||||
memset( szDeviceName, 0, 1024*sizeof(char) );
|
||||
sprintf( szDeviceName, "%s", strlwr( szDriverName ) );
|
||||
|
||||
//
|
||||
// load PSAPI routines
|
||||
//
|
||||
if( false == LoadPSAPIRoutines() )
|
||||
return false;
|
||||
|
||||
//
|
||||
// enumerate devices
|
||||
//
|
||||
if( FALSE == EnumDeviceDrivers( lpDevices, dSize, &dDevicesSize ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// walk trough and compare see if the device driver exists
|
||||
//
|
||||
for( int k( dDevicesSize / sizeof( LPVOID ) ); k >= 0; k-- )
|
||||
{
|
||||
memset( szCurrentDeviceName, 0, 1024*sizeof(char) );
|
||||
memset( tszCurrentDeviceName, 0, 1024*sizeof(TCHAR) );
|
||||
|
||||
if( 0 != GetDeviceDriverBaseName( lpDevices[ k ], tszCurrentDeviceName, dNameSize ) )
|
||||
{
|
||||
sprintf( szCurrentDeviceName, "%S", tszCurrentDeviceName );
|
||||
|
||||
if( 0 == strcmp( strlwr( szCurrentDeviceName ), szDeviceName ) )
|
||||
{
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// free PSAPI routines
|
||||
//
|
||||
FreePSAPIRoutines();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
extern "C" __declspec(dllexport) void FindProcess( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop )
|
||||
{
|
||||
char szParameter[ 1024 ];
|
||||
|
||||
|
||||
g_hwndParent = hwndParent;
|
||||
|
||||
EXDLL_INIT();
|
||||
{
|
||||
popstring( szParameter );
|
||||
|
||||
if( true == FindProc( szParameter ) )
|
||||
wsprintf( szParameter, "1" );
|
||||
else
|
||||
wsprintf( szParameter, "0" );
|
||||
|
||||
setuservariable( INST_R0, szParameter );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
extern "C" __declspec(dllexport) void KillProcess( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop )
|
||||
{
|
||||
char szParameter[ 1024 ];
|
||||
|
||||
|
||||
g_hwndParent = hwndParent;
|
||||
|
||||
EXDLL_INIT();
|
||||
{
|
||||
popstring( szParameter );
|
||||
|
||||
if( true == KillProc( szParameter ) )
|
||||
wsprintf( szParameter, "1" );
|
||||
else
|
||||
wsprintf( szParameter, "0" );
|
||||
|
||||
setuservariable( INST_R0, szParameter );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
extern "C" __declspec(dllexport) void FindDevice( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop )
|
||||
{
|
||||
char szParameter[ 1024 ];
|
||||
|
||||
|
||||
g_hwndParent = hwndParent;
|
||||
|
||||
EXDLL_INIT();
|
||||
{
|
||||
popstring( szParameter );
|
||||
|
||||
if( true == FindDev( szParameter ) )
|
||||
wsprintf( szParameter, "1" );
|
||||
else
|
||||
wsprintf( szParameter, "0" );
|
||||
|
||||
setuservariable( INST_R0, szParameter );
|
||||
}
|
||||
}
|
49
admin/win/nsi/nsis_processes/src/processes.h
Executable file
49
admin/win/nsi/nsis_processes/src/processes.h
Executable file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// PSAPI function pointers
|
||||
typedef BOOL (WINAPI *lpfEnumProcesses) ( DWORD *, DWORD, DWORD * );
|
||||
typedef BOOL (WINAPI *lpfEnumProcessModules) ( HANDLE, HMODULE *, DWORD, LPDWORD );
|
||||
typedef DWORD (WINAPI *lpfGetModuleBaseName) ( HANDLE, HMODULE, LPTSTR, DWORD );
|
||||
typedef BOOL (WINAPI *lpfEnumDeviceDrivers) ( LPVOID *, DWORD, LPDWORD );
|
||||
typedef BOOL (WINAPI *lpfGetDeviceDriverBaseName)( LPVOID, LPTSTR, DWORD );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Internal use routines
|
||||
bool LoadPSAPIRoutines( void );
|
||||
bool FreePSAPIRoutines( void );
|
||||
|
||||
bool FindProc( char *szProcess );
|
||||
bool KillProc( char *szProcess );
|
||||
|
||||
bool FindDev( char *szDriverName );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Exported routines
|
||||
extern "C" __declspec(dllexport) void FindProcess( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop );
|
||||
|
||||
extern "C" __declspec(dllexport) void KillProcess( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop );
|
||||
|
||||
extern "C" __declspec(dllexport) void FindDevice( HWND hwndParent,
|
||||
int string_size,
|
||||
char *variables,
|
||||
stack_t **stacktop );
|
BIN
admin/win/nsi/nsis_processes/src/processes.ncb
Executable file
BIN
admin/win/nsi/nsis_processes/src/processes.ncb
Executable file
Binary file not shown.
103
admin/win/nsi/nsis_processes/src/processes.rc
Executable file
103
admin/win/nsi/nsis_processes/src/processes.rc
Executable file
@@ -0,0 +1,103 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments", "NSIS Plug-in for Windows process management. Only WinNT, Win2K, WinXP and Win2003 Server supported."
|
||||
VALUE "CompanyName", "Andrei Ciubotaru [Hardwired]"
|
||||
VALUE "FileDescription", "Windows Processes Management"
|
||||
VALUE "FileVersion", "1, 0, 0, 1"
|
||||
VALUE "InternalName", "Processes"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2004 Hardwired. No rights reserved."
|
||||
VALUE "OriginalFilename", "Processes.dll"
|
||||
VALUE "ProductName", "Processes"
|
||||
VALUE "ProductVersion", "1, 0, 0, 1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
21
admin/win/nsi/nsis_processes/src/processes.sln
Executable file
21
admin/win/nsi/nsis_processes/src/processes.sln
Executable file
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "processes", "processes.vcproj", "{3438467F-A719-46DC-93E5-137A8B691727}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{3438467F-A719-46DC-93E5-137A8B691727}.Debug.ActiveCfg = Debug|Win32
|
||||
{3438467F-A719-46DC-93E5-137A8B691727}.Debug.Build.0 = Debug|Win32
|
||||
{3438467F-A719-46DC-93E5-137A8B691727}.Release.ActiveCfg = Release|Win32
|
||||
{3438467F-A719-46DC-93E5-137A8B691727}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
122
admin/win/nsi/nsis_processes/src/processes.txt
Executable file
122
admin/win/nsi/nsis_processes/src/processes.txt
Executable file
@@ -0,0 +1,122 @@
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
||||
Processes (Processes.dll)
|
||||
Version: 1.0.0.1
|
||||
Release: 12.december.2004
|
||||
Description:Nullsoft Installer (NSIS) plug-in for managing?!
|
||||
Windows processes.
|
||||
|
||||
Copyright: <09> 2004 Hardwired. No rights reserved.
|
||||
There is no restriction and no guaranty for using
|
||||
this software.
|
||||
|
||||
Author: Andrei Ciubotaru [Hardwired]
|
||||
Lead Developer ICode&Ideas SRL (http://www.icode.ro)
|
||||
hardwiredteks@gmail.com, hardwired@icode.ro
|
||||
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
||||
INTRODUCTION
|
||||
|
||||
The Need For Plug-in - I need it for the one of my installers.
|
||||
|
||||
Briefly: Use it when you need to find\kill a process when
|
||||
installing\uninstalling some application. Also, use it when you
|
||||
need to test the presence of a device driver.
|
||||
|
||||
|
||||
SUPPORT
|
||||
|
||||
Supported platforms are: WinNT,Win2K,WinXP and Win2003 Server.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Processes::FindProcess <process_name.exe>
|
||||
|
||||
Searches the currently running processes for the given
|
||||
process name.
|
||||
|
||||
return: 1 - the process was found
|
||||
0 - the process was not found
|
||||
|
||||
Processes::KillProcess <process_name.exe>
|
||||
|
||||
Searches the currently running processes for the given
|
||||
process name. If the process is found then the it gets
|
||||
killed.
|
||||
|
||||
return: 1 - the process was found and killed
|
||||
0 - the process was not found or the process
|
||||
cannot be killed (insuficient rights)
|
||||
|
||||
Processes::FindDevice <device_base_name>
|
||||
|
||||
Searches the installed devices drivers for the given
|
||||
device base name.
|
||||
(important: I said BASE NAME not FILENAME)
|
||||
|
||||
return: 1 - the device driver was found
|
||||
0 - the device driver was not found
|
||||
|
||||
|
||||
USAGE
|
||||
|
||||
First of all, does not matter where you use it. Ofcourse, the
|
||||
routines must be called inside of a Section/Function scope.
|
||||
|
||||
Processes::FindProcess "process_name.exe"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" make_my_day noooooo
|
||||
|
||||
make_my_day:
|
||||
...
|
||||
|
||||
noooooo:
|
||||
...
|
||||
|
||||
|
||||
Processes::KillProcess "process_name.exe"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" dead_meat why_wont_you_die
|
||||
|
||||
dead_meat:
|
||||
...
|
||||
|
||||
why_wont_you_die:
|
||||
...
|
||||
|
||||
|
||||
Processes::FindDevice "device_base_name"
|
||||
Pop $R0
|
||||
|
||||
StrCmp $R0 "1" blabla more_blabla
|
||||
|
||||
blabla:
|
||||
...
|
||||
|
||||
more_blabla:
|
||||
...
|
||||
|
||||
|
||||
THANKS
|
||||
|
||||
Sunil Kamath for inspiring me. I wanted to use its FindProcDLL
|
||||
but my requirements made it imposible.
|
||||
|
||||
Nullsoft for creating this very powerfull installer. One big,
|
||||
free and full-featured (hmmm... and guiless for the moment) mean
|
||||
install machine!:)
|
||||
|
||||
ME for being such a great coder...
|
||||
... HAHAHAHAHAHAHA!
|
||||
|
||||
ONE MORE THING
|
||||
|
||||
If you use the plugin or it's source-code, I would apreciate
|
||||
if my name is mentioned.
|
||||
|
||||
----------------------------------------------------------------
|
||||
----------------------------------------------------------------
|
222
admin/win/nsi/nsis_processes/src/processes.vcproj
Executable file
222
admin/win/nsi/nsis_processes/src/processes.vcproj
Executable file
@@ -0,0 +1,222 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="processes"
|
||||
SccProjectName="processes"
|
||||
SccLocalPath=".">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\Debug"
|
||||
IntermediateDirectory=".\Debug"
|
||||
ConfigurationType="2"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FINDPROCDLL_EXPORTS"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
PrecompiledHeaderFile=".\Debug/processes.pch"
|
||||
AssemblerListingLocation=".\Debug/"
|
||||
ObjectFile=".\Debug/"
|
||||
ProgramDataBaseFileName=".\Debug/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile=".\Debug/processes.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile=".\Debug/processes.pdb"
|
||||
ImportLibrary=".\Debug/processes.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
MkTypLibCompatible="TRUE"
|
||||
SuppressStartupBanner="TRUE"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName=".\Debug/processes.tlb"
|
||||
HeaderFileName=""/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1034"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="..\bin"
|
||||
IntermediateDirectory="..\bin\processes"
|
||||
ConfigurationType="2"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
GlobalOptimizations="TRUE"
|
||||
InlineFunctionExpansion="1"
|
||||
FavorSizeOrSpeed="1"
|
||||
OptimizeForWindowsApplication="TRUE"
|
||||
PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;FINDPROCDLL_EXPORTS"
|
||||
StringPooling="TRUE"
|
||||
RuntimeLibrary="0"
|
||||
StructMemberAlignment="1"
|
||||
EnableFunctionLevelLinking="TRUE"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
PrecompiledHeaderFile="..\bin\processes/processes.pch"
|
||||
AssemblerListingLocation="..\bin\processes/"
|
||||
ObjectFile="..\bin\processes/"
|
||||
ProgramDataBaseFileName="..\bin\processes/"
|
||||
WarningLevel="4"
|
||||
SuppressStartupBanner="TRUE"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="libc.lib"
|
||||
OutputFile="..\bin/Processes.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
IgnoreAllDefaultLibraries="FALSE"
|
||||
ProgramDatabaseFile="..\bin/processes.pdb"
|
||||
OptimizeForWindows98="1"
|
||||
ImportLibrary="..\bin/processes.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
MkTypLibCompatible="TRUE"
|
||||
SuppressStartupBanner="TRUE"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName=".\Release/processes.tlb"
|
||||
HeaderFileName=""/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="1033"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
||||
<File
|
||||
RelativePath="processes.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;FINDPROCDLL_EXPORTS;$(NoInherit)"
|
||||
BasicRuntimeChecks="3"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="1"
|
||||
PreprocessorDefinitions="NDEBUG;_WINDOWS;_MBCS;_USRDLL;FINDPROCDLL_EXPORTS;$(NoInherit)"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\processes.rc">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StdAfx.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;FINDPROCDLL_EXPORTS;$(NoInherit)"
|
||||
BasicRuntimeChecks="3"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="1"
|
||||
PreprocessorDefinitions="NDEBUG;_WINDOWS;_MBCS;_USRDLL;FINDPROCDLL_EXPORTS;$(NoInherit)"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl">
|
||||
<File
|
||||
RelativePath="exdll.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\processes.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\resource.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StdAfx.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="processes.txt">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
15
admin/win/nsi/nsis_processes/src/resource.h
Executable file
15
admin/win/nsi/nsis_processes/src/resource.h
Executable file
@@ -0,0 +1,15 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by processes.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
0
admin/win/nsi/page_header.bmp
Executable file → Normal file
0
admin/win/nsi/page_header.bmp
Executable file → Normal file
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -1 +1 @@
|
||||
96
|
||||
100
|
0
admin/win/nsi/tomahawk.ini
Executable file → Normal file
0
admin/win/nsi/tomahawk.ini
Executable file → Normal file
97
admin/win/nsi/tomahawk.nsi
Executable file → Normal file
97
admin/win/nsi/tomahawk.nsi
Executable file → Normal file
@@ -4,12 +4,12 @@
|
||||
; Some installer script options (comment-out options not required)
|
||||
;-----------------------------------------------------------------------------
|
||||
;!define OPTION_LICENSE_AGREEMENT
|
||||
;!define OPTION_UAC_PLUGIN_ENHANCED
|
||||
!define OPTION_UAC_PLUGIN_ENHANCED
|
||||
!define OPTION_SECTION_SC_START_MENU
|
||||
!define OPTION_SECTION_SC_DESKTOP
|
||||
!define OPTION_SECTION_SC_QUICK_LAUNCH
|
||||
!define OPTION_FINISHPAGE
|
||||
!define OPTION_FINISHPAGE_LAUNCHER
|
||||
;!define OPTION_FINISHPAGE_LAUNCHER
|
||||
!define OPTION_FINISHPAGE_RELEASE_NOTES
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
!define VER_MAJOR "0"
|
||||
!define VER_MINOR "0"
|
||||
!define VER_BUILD "2"
|
||||
!define VER_BUILD "3"
|
||||
|
||||
!define VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}"
|
||||
|
||||
@@ -58,17 +58,10 @@ InstType Full
|
||||
InstType Minimal
|
||||
CRCCheck On
|
||||
SetCompressor /SOLID lzma
|
||||
RequestExecutionLevel user ;Now using the UAC plugin.
|
||||
ReserveFile tomahawk.ini
|
||||
ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
||||
|
||||
;The UAC plugin provides an elevated user.
|
||||
;Otherwise request admin level here.
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
RequestExecutionLevel user
|
||||
!else
|
||||
RequestExecutionLevel admin
|
||||
!endif
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Include some required header files.
|
||||
;-----------------------------------------------------------------------------
|
||||
@@ -79,9 +72,7 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
||||
!include Memento.nsh ;Remember user selections.
|
||||
!include WinVer.nsh ;Windows version detection.
|
||||
!include WordFunc.nsh ;Used by VersionCompare macro function.
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
!include UAC.nsh ;Used by the UAC elevation to install as user or admin.
|
||||
!endif
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Memento selections stored in registry.
|
||||
@@ -146,18 +137,46 @@ UninstPage custom un.UnPageUserAppData un.UnPageUserAppDataLeave
|
||||
##############################################################################
|
||||
|
||||
Function LaunchTomahawk
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
${UAC.CallFunctionAsUser} LaunchTomahawkAsUser
|
||||
!else
|
||||
Exec "$INSTDIR\tomahawk.exe"
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
Function LaunchTomahawkAsUser
|
||||
Exec "$INSTDIR\tomahawk.exe"
|
||||
FunctionEnd
|
||||
!endif
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# PROCESS HANDLING FUNCTIONS AND MACROS #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
!macro CheckForProcess processName gotoWhenFound gotoWhenNotFound
|
||||
Processes::FindProcess ${processName}
|
||||
StrCmp $R0 "0" ${gotoWhenNotFound} ${gotoWhenFound}
|
||||
!macroend
|
||||
|
||||
!macro ConfirmEndProcess processName
|
||||
MessageBox MB_YESNO|MB_ICONEXCLAMATION \
|
||||
"Found ${processName} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?" \
|
||||
IDYES process_${processName}_kill IDNO process_${processName}_ended
|
||||
process_${processName}_kill:
|
||||
DetailPrint "Killing ${processName} processes."
|
||||
Processes::KillProcess ${processName}
|
||||
Sleep 1500
|
||||
StrCmp $R0 "1" process_${processName}_ended
|
||||
DetailPrint "Process to kill not found!"
|
||||
process_${processName}_ended:
|
||||
!macroend
|
||||
|
||||
!macro CheckAndConfirmEndProcess processName
|
||||
!insertmacro CheckForProcess ${processName} 0 no_process_${processName}_to_end
|
||||
!insertmacro ConfirmEndProcess ${processName}
|
||||
no_process_${processName}_to_end:
|
||||
!macroend
|
||||
|
||||
Function EnsureTomahawkShutdown
|
||||
!insertmacro CheckAndConfirmEndProcess "tomahawk.exe"
|
||||
FunctionEnd
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
@@ -226,12 +245,10 @@ Function PageLeaveReinstall
|
||||
Delete $R1
|
||||
RMDir $INSTDIR
|
||||
no_remove_uninstaller:
|
||||
StrCmp $R0 "2" +2 0
|
||||
BringToFront
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
StrCmp $R0 "2" 0 +3
|
||||
UAC::Unload
|
||||
Quit
|
||||
!endif
|
||||
BringToFront
|
||||
reinst_done:
|
||||
FunctionEnd
|
||||
|
||||
@@ -346,7 +363,7 @@ SectionGroup "Shortcuts"
|
||||
CreateShortCut "$SMPROGRAMS\Tomahawk\LICENSE.lnk" "$INSTDIR\LICENSE.txt"
|
||||
CreateShortCut "$SMPROGRAMS\Tomahawk\Tomahawk.lnk" "$INSTDIR\tomahawk.exe"
|
||||
CreateShortCut "$SMPROGRAMS\Tomahawk\Release notes.lnk" "$INSTDIR\NOTES.txt"
|
||||
CreateShortCut "$SMPROGRAMS\Tomahawk\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
CreateShortCut "$SMPROGRAMS\Tomahawk\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
||||
SetShellVarContext current
|
||||
${MementoSectionEnd}
|
||||
!endif
|
||||
@@ -390,7 +407,7 @@ Section -post
|
||||
SetDetailsPrint textonly
|
||||
DetailPrint "Writing Uninstaller"
|
||||
SetDetailsPrint listonly
|
||||
WriteUninstaller $INSTDIR\Uninstall.exe
|
||||
WriteUninstaller $INSTDIR\uninstall.exe
|
||||
|
||||
;Registry keys required for installer version handling and uninstaller.
|
||||
SetDetailsPrint textonly
|
||||
@@ -418,6 +435,12 @@ Section -post
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "NoModify" "1"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "NoRepair" "1"
|
||||
|
||||
; Register tomahawk:// protocol handler
|
||||
WriteRegStr HKCR "tomahawk" "" "URL: Tomahawk Protocol"
|
||||
WriteRegStr HKCR "tomahawk\DefaultIcon" "" $INSTDIR\tomahawk.exe,1
|
||||
WriteRegStr HKCR "tomahawk\shell" "" "open"
|
||||
WriteRegStr HKCR "tomahawk\shell\open\command" "" '"$INSTDIR\tomahawk.exe" "%1"'
|
||||
|
||||
SetDetailsPrint textonly
|
||||
DetailPrint "Finsihed."
|
||||
SectionEnd
|
||||
@@ -477,6 +500,8 @@ Section Uninstall
|
||||
DeleteRegValue HKLM "Software\Tomahawk" ""
|
||||
DeleteRegKey HKLM "Software\Tomahawk"
|
||||
|
||||
DeleteRegKey HKCR "tomahawk"
|
||||
|
||||
;Start menu shortcuts.
|
||||
!ifdef OPTION_SECTION_SC_START_MENU
|
||||
SetShellVarContext all
|
||||
@@ -526,7 +551,6 @@ Function .onInit
|
||||
|
||||
${MementoSectionRestore}
|
||||
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC_Elevate:
|
||||
UAC::RunElevated
|
||||
StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user?
|
||||
@@ -546,7 +570,6 @@ Function .onInit
|
||||
StrCmp 3 $1 0 UAC_ElevationAborted ;Try again?
|
||||
MessageBox MB_ICONSTOP "This installer requires admin access, try again"
|
||||
goto UAC_Elevate
|
||||
!endif
|
||||
|
||||
;Prevent multiple instances.
|
||||
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "tomahawkInstaller") i .r1 ?e'
|
||||
@@ -554,19 +577,25 @@ Function .onInit
|
||||
StrCmp $R0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running."
|
||||
Abort
|
||||
|
||||
;Use available InstallLocation when possible. This is useful in the uninstaller
|
||||
;via re-install, which would otherwise use a default location - a bug.
|
||||
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "InstallLocation"
|
||||
StrCmp $R0 "" SkipSetInstDir
|
||||
StrCpy $INSTDIR $R0
|
||||
SkipSetInstDir:
|
||||
|
||||
;Shutdown Tomahawk in case Add/Remove re-installer option used.
|
||||
Call EnsureTomahawkShutdown
|
||||
FunctionEnd
|
||||
|
||||
Function .onInstSuccess
|
||||
${MementoSectionSave}
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC::Unload ;Must call unload!
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
||||
Function .onInstFailed
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC::Unload ;Must call unload!
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
||||
##############################################################################
|
||||
@@ -576,7 +605,6 @@ FunctionEnd
|
||||
##############################################################################
|
||||
|
||||
Function un.onInit
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC_Elevate:
|
||||
UAC::RunElevated
|
||||
StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user?
|
||||
@@ -596,7 +624,6 @@ Function un.onInit
|
||||
StrCmp 3 $1 0 UAC_ElevationAborted ;Try again?
|
||||
MessageBox MB_ICONSTOP "This uninstaller requires admin access, try again"
|
||||
goto UAC_Elevate
|
||||
!endif
|
||||
|
||||
;Prevent multiple instances.
|
||||
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "tomahawkUninstaller") i .r1 ?e'
|
||||
@@ -607,13 +634,9 @@ Function un.onInit
|
||||
FunctionEnd
|
||||
|
||||
Function un.onUnInstSuccess
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC::Unload ;Must call unload!
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
||||
Function un.onUnInstFailed
|
||||
!ifdef OPTION_UAC_PLUGIN_ENHANCED
|
||||
UAC::Unload ;Must call unload!
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
0
admin/win/nsi/welcome.bmp
Executable file → Normal file
0
admin/win/nsi/welcome.bmp
Executable file → Normal file
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
@@ -19,6 +19,7 @@
|
||||
#ifndef TOMAHAWK_INFOSYSTEM_H
|
||||
#define TOMAHAWK_INFOSYSTEM_H
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QtDebug>
|
||||
#include <QtCore/QMap>
|
||||
@@ -93,7 +94,8 @@ enum InfoType {
|
||||
|
||||
typedef QMap< InfoType, QVariant > InfoMap;
|
||||
typedef QMap< QString, QMap< QString, QString > > InfoGenericMap;
|
||||
typedef QHash< QString, QVariant > InfoCustomDataHash;
|
||||
typedef QHash< QString, QVariant > InfoCustomData;
|
||||
typedef QHash< QString, QString > InfoCacheCriteria;
|
||||
|
||||
class InfoPlugin : public QObject
|
||||
{
|
||||
@@ -107,15 +109,19 @@ public:
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
virtual void getInfo( const QString &caller, const InfoType type, const QVariant &data, Tomahawk::InfoSystem::InfoCustomDataHash customData ) = 0;
|
||||
virtual void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData ) = 0;
|
||||
|
||||
signals:
|
||||
void info( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData );
|
||||
void getCachedInfo( QHash< QString, QString > criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData );
|
||||
void getCachedInfo( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void updateCache( Tomahawk::InfoSystem::InfoCacheCriteria criteria, Tomahawk::InfoSystem::InfoType type, QVariant output );
|
||||
void info( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void finished( QString, Tomahawk::InfoSystem::InfoType );
|
||||
|
||||
//public slots:
|
||||
//void notInCacheSlot( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData ) = 0;
|
||||
public slots:
|
||||
//FIXME: Make pure virtual when everything supports it
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
InfoType m_type;
|
||||
@@ -134,18 +140,17 @@ public:
|
||||
|
||||
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &types );
|
||||
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData );
|
||||
void getInfo( const QString &caller, const InfoMap &input, InfoCustomDataHash customData );
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData );
|
||||
void getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData );
|
||||
|
||||
InfoSystemCache* getCache() { return m_cache; }
|
||||
|
||||
signals:
|
||||
void info( QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData );
|
||||
void info( QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void finished( QString target );
|
||||
|
||||
public slots:
|
||||
void infoSlot( QString target, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData );
|
||||
void finishedSlot( QString target,Tomahawk::InfoSystem::InfoType type);
|
||||
void infoSlot( QString target, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
|
||||
private:
|
||||
QLinkedList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
|
||||
@@ -155,7 +160,7 @@ private:
|
||||
// For now, statically instantiate plugins; this is just somewhere to keep them
|
||||
QLinkedList< InfoPluginPtr > m_plugins;
|
||||
|
||||
QHash< QString, QHash< Tomahawk::InfoSystem::InfoType, int > > m_dataTracker;
|
||||
QHash< QString, QHash< InfoType, int > > m_dataTracker;
|
||||
|
||||
InfoSystemCache* m_cache;
|
||||
QThread* m_infoSystemCacheThreadController;
|
||||
@@ -165,7 +170,26 @@ private:
|
||||
|
||||
}
|
||||
|
||||
inline uint qHash( Tomahawk::InfoSystem::InfoCacheCriteria hash )
|
||||
{
|
||||
QCryptographicHash md5( QCryptographicHash::Md5 );
|
||||
foreach( QString key, hash.keys() )
|
||||
md5.addData( key.toUtf8() );
|
||||
foreach( QString value, hash.values() )
|
||||
md5.addData( value.toUtf8() );
|
||||
|
||||
QString hexData = md5.result();
|
||||
|
||||
uint returnval = 0;
|
||||
|
||||
foreach( uint val, hexData.toUcs4() )
|
||||
returnval += val;
|
||||
|
||||
return returnval;
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoGenericMap );
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCustomDataHash );
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCustomData );
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCacheCriteria );
|
||||
|
||||
#endif // TOMAHAWK_INFOSYSTEM_H
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "network/servent.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "kdsingleapplicationguard/kdsingleapplicationguard.h"
|
||||
|
||||
class AudioEngine;
|
||||
class Database;
|
||||
@@ -98,9 +99,11 @@ public:
|
||||
// because QApplication::arguments() is expensive
|
||||
bool scrubFriendlyName() const { return m_scrubFriendlyName; }
|
||||
|
||||
public slots:
|
||||
void instanceStarted( KDSingleApplicationGuard::Instance );
|
||||
|
||||
private slots:
|
||||
void setupSIP();
|
||||
void messageReceived( const QString& );
|
||||
|
||||
private:
|
||||
void initLocalCollection();
|
||||
|
1484
lang/tomahawk_de.ts
Normal file
1484
lang/tomahawk_de.ts
Normal file
File diff suppressed because it is too large
Load Diff
5
lang/tomahawk_i18n.qrc
Normal file
5
lang/tomahawk_i18n.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>tomahawk_de.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
25
lang/translations.cmake
Normal file
25
lang/translations.cmake
Normal file
@@ -0,0 +1,25 @@
|
||||
FILE (GLOB TS_FILES ${CMAKE_SOURCE_DIR}/lang/*.ts)
|
||||
QT4_ADD_TRANSLATION(QM_FILES ${TS_FILES})
|
||||
|
||||
## HACK HACK HACK - around rcc limitations to allow out of source-tree building
|
||||
SET( trans_file tomahawk_i18n )
|
||||
SET( trans_srcfile ${CMAKE_SOURCE_DIR}/lang/${trans_file}.qrc)
|
||||
SET( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc)
|
||||
SET( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx)
|
||||
|
||||
# Copy the QRC file to the output directory
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${trans_infile}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${trans_srcfile} ${trans_infile}
|
||||
MAIN_DEPENDENCY ${trans_srcfile}
|
||||
)
|
||||
|
||||
# Run the resource compiler (rcc_options should already be set)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${trans_outfile}
|
||||
COMMAND ${QT_RCC_EXECUTABLE}
|
||||
ARGS ${rcc_options} -name ${trans_file} -o ${trans_outfile} ${trans_infile}
|
||||
MAIN_DEPENDENCY ${trans_infile}
|
||||
DEPENDS ${QM_FILES}
|
||||
)
|
||||
|
@@ -186,7 +186,9 @@ qt4_wrap_cpp( tomahawkMoc ${tomahawkHeaders} )
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${tomahawkHeaders} )
|
||||
include( ${CMAKE_SOURCE_DIR}/lang/translations.cmake )
|
||||
|
||||
SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${tomahawkHeaders} ${trans_outfile})
|
||||
|
||||
IF( "${gui}" STREQUAL "no" )
|
||||
ELSE()
|
||||
|
@@ -168,8 +168,8 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
connect( TomahawkApp::instance()->infoSystem(),
|
||||
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) ),
|
||||
SLOT( infoSystemInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) ) );
|
||||
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
SLOT( infoSystemInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ) );
|
||||
|
||||
connect( TomahawkApp::instance()->infoSystem(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) );
|
||||
|
||||
@@ -252,17 +252,17 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
QString artistName = result->artist()->name();
|
||||
QString albumName = result->album()->name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoCustomDataHash trackInfo;
|
||||
Tomahawk::InfoSystem::InfoCustomData trackInfo;
|
||||
|
||||
trackInfo["artist"] = QVariant::fromValue< QString >( result->artist()->name() );
|
||||
trackInfo["album"] = QVariant::fromValue< QString >( result->album()->name() );
|
||||
TomahawkApp::instance()->infoSystem()->getInfo(
|
||||
s_infoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomDataHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomDataHash() );
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
|
||||
}
|
||||
|
||||
void
|
||||
AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData )
|
||||
AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( caller != s_infoIdentifier || type != Tomahawk::InfoSystem::InfoAlbumCoverArt )
|
||||
@@ -277,13 +277,13 @@ AudioControls::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType ty
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !output.canConvert< Tomahawk::InfoSystem::InfoCustomDataHash >() )
|
||||
if ( !output.canConvert< Tomahawk::InfoSystem::InfoCustomData >() )
|
||||
{
|
||||
qDebug() << "Cannot convert fetched art from a QByteArray";
|
||||
return;
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoCustomDataHash returnedData = output.value< Tomahawk::InfoSystem::InfoCustomDataHash >();
|
||||
Tomahawk::InfoSystem::InfoCustomData returnedData = output.value< Tomahawk::InfoSystem::InfoCustomData >();
|
||||
const QByteArray ba = returnedData["imgbytes"].toByteArray();
|
||||
if ( ba.length() )
|
||||
{
|
||||
|
@@ -45,7 +45,7 @@ signals:
|
||||
public slots:
|
||||
void onRepeatModeChanged( PlaylistInterface::RepeatMode mode );
|
||||
void onShuffleModeChanged( bool enabled );
|
||||
void infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData );
|
||||
void infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void infoSystemFinished( QString target );
|
||||
|
||||
protected:
|
||||
|
@@ -21,14 +21,14 @@
|
||||
|
||||
#ifdef ENABLE_HEADLESS
|
||||
|
||||
#define TOMAHAWK_APPLICATION QtSingleCoreApplication
|
||||
#define TOMAHAWK_APPLICATION QCoreApplication
|
||||
#define TOMAHAWK_HEADLESS
|
||||
#include "qtsingleapp/qtsingleapplication.h"
|
||||
#include <QApplication>>
|
||||
|
||||
#else
|
||||
|
||||
#define TOMAHAWK_APPLICATION QtSingleApplication
|
||||
#include "qtsingleapp/qtsingleapplication.h"
|
||||
#define TOMAHAWK_APPLICATION QApplication
|
||||
#include <QApplication>
|
||||
#include "tomahawkwindow.h"
|
||||
|
||||
#endif
|
||||
|
@@ -41,7 +41,7 @@ EchoNestPlugin::~EchoNestPlugin()
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash customData)
|
||||
void EchoNestPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomData customData)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -65,7 +65,7 @@ void EchoNestPlugin::getInfo(const QString &caller, const InfoType type, const Q
|
||||
}
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getSongProfile(const QString &caller, const QVariant& data, InfoCustomDataHash &customData, const QString &item)
|
||||
void EchoNestPlugin::getSongProfile(const QString &caller, const QVariant& data, InfoCustomData &customData, const QString &item)
|
||||
{
|
||||
//WARNING: Totally not implemented yet
|
||||
|
||||
@@ -80,7 +80,7 @@ void EchoNestPlugin::getSongProfile(const QString &caller, const QVariant& data,
|
||||
// connect(reply, SIGNAL(finished()), SLOT(getArtistBiographySlot()));
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getArtistBiography(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
void EchoNestPlugin::getArtistBiography(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if( !isValidArtistData( caller, data, customData ) )
|
||||
return;
|
||||
@@ -94,7 +94,7 @@ void EchoNestPlugin::getArtistBiography(const QString &caller, const QVariant& d
|
||||
connect(reply, SIGNAL(finished()), SLOT(getArtistBiographySlot()));
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getArtistFamiliarity(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
void EchoNestPlugin::getArtistFamiliarity(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if( !isValidArtistData( caller, data, customData ) )
|
||||
return;
|
||||
@@ -109,7 +109,7 @@ void EchoNestPlugin::getArtistFamiliarity(const QString &caller, const QVariant&
|
||||
connect(reply, SIGNAL(finished()), SLOT(getArtistFamiliaritySlot()));
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getArtistHotttnesss(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
void EchoNestPlugin::getArtistHotttnesss(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if( !isValidArtistData( caller, data, customData ) )
|
||||
return;
|
||||
@@ -123,7 +123,7 @@ void EchoNestPlugin::getArtistHotttnesss(const QString &caller, const QVariant&
|
||||
connect(reply, SIGNAL(finished()), SLOT(getArtistHotttnesssSlot()));
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getArtistTerms(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
void EchoNestPlugin::getArtistTerms(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if( !isValidArtistData( caller, data, customData ) )
|
||||
return;
|
||||
@@ -137,7 +137,7 @@ void EchoNestPlugin::getArtistTerms(const QString &caller, const QVariant& data,
|
||||
connect(reply, SIGNAL(finished()), SLOT(getArtistTermsSlot()));
|
||||
}
|
||||
|
||||
void EchoNestPlugin::getMiscTopTerms(const QString &caller, const QVariant& data, InfoCustomDataHash& customData)
|
||||
void EchoNestPlugin::getMiscTopTerms(const QString &caller, const QVariant& data, InfoCustomData& customData)
|
||||
{
|
||||
QNetworkReply* reply = Echonest::Artist::topTerms( 20 );
|
||||
m_replyMap[reply] = customData;
|
||||
@@ -163,7 +163,6 @@ void EchoNestPlugin::getArtistBiographySlot()
|
||||
|
||||
}
|
||||
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistBiography, reply->property( "data" ), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(biographyMap), m_replyMap[reply] );
|
||||
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistBiography);
|
||||
m_replyMap.remove(reply);
|
||||
m_callerMap.remove(reply);
|
||||
reply->deleteLater();
|
||||
@@ -175,7 +174,6 @@ void EchoNestPlugin::getArtistFamiliaritySlot()
|
||||
Echonest::Artist artist = artistFromReply( reply );
|
||||
qreal familiarity = artist.familiarity();
|
||||
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistFamiliarity, reply->property( "data" ), familiarity, m_replyMap[reply] );
|
||||
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistFamiliarity);
|
||||
m_replyMap.remove(reply);
|
||||
m_callerMap.remove(reply);
|
||||
reply->deleteLater();
|
||||
@@ -187,7 +185,6 @@ void EchoNestPlugin::getArtistHotttnesssSlot()
|
||||
Echonest::Artist artist = artistFromReply( reply );
|
||||
qreal hotttnesss = artist.hotttnesss();
|
||||
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistHotttness, reply->property( "data" ), hotttnesss, m_replyMap[reply] );
|
||||
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistHotttness);
|
||||
m_replyMap.remove(reply);
|
||||
m_callerMap.remove(reply);
|
||||
reply->deleteLater();
|
||||
@@ -206,7 +203,6 @@ void EchoNestPlugin::getArtistTermsSlot()
|
||||
termsMap[ term.name() ] = termMap;
|
||||
}
|
||||
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistTerms, reply->property( "data" ), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(termsMap), m_replyMap[reply] );
|
||||
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistTerms);
|
||||
m_replyMap.remove(reply);
|
||||
m_callerMap.remove(reply);
|
||||
reply->deleteLater();
|
||||
@@ -224,13 +220,12 @@ void EchoNestPlugin::getMiscTopSlot()
|
||||
termsMap[ term.name().toLower() ] = termMap;
|
||||
}
|
||||
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoMiscTopTerms, QVariant(), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(termsMap), m_replyMap[reply] );
|
||||
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoMiscTopTerms);
|
||||
m_replyMap.remove(reply);
|
||||
m_callerMap.remove(reply);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
bool EchoNestPlugin::isValidArtistData(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
bool EchoNestPlugin::isValidArtistData(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if (data.isNull() || !data.isValid() || !data.canConvert<QString>())
|
||||
{
|
||||
@@ -246,7 +241,7 @@ bool EchoNestPlugin::isValidArtistData(const QString &caller, const QVariant& da
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EchoNestPlugin::isValidTrackData(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
|
||||
bool EchoNestPlugin::isValidTrackData(const QString &caller, const QVariant& data, InfoCustomData &customData)
|
||||
{
|
||||
if (data.isNull() || !data.isValid() || !data.canConvert<QString>())
|
||||
{
|
||||
|
@@ -42,18 +42,18 @@ public:
|
||||
EchoNestPlugin(QObject *parent);
|
||||
virtual ~EchoNestPlugin();
|
||||
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData );
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData );
|
||||
|
||||
private:
|
||||
void getSongProfile( const QString &caller, const QVariant &data, InfoCustomDataHash &customData, const QString &item = QString() );
|
||||
void getArtistBiography ( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
|
||||
void getArtistFamiliarity( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
|
||||
void getArtistHotttnesss( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
|
||||
void getArtistTerms( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
|
||||
void getMiscTopTerms( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
|
||||
void getSongProfile( const QString &caller, const QVariant &data, InfoCustomData &customData, const QString &item = QString() );
|
||||
void getArtistBiography ( const QString &caller, const QVariant &data, InfoCustomData &customData );
|
||||
void getArtistFamiliarity( const QString &caller, const QVariant &data, InfoCustomData &customData );
|
||||
void getArtistHotttnesss( const QString &caller, const QVariant &data, InfoCustomData &customData );
|
||||
void getArtistTerms( const QString &caller, const QVariant &data, InfoCustomData &customData );
|
||||
void getMiscTopTerms( const QString &caller, const QVariant &data, InfoCustomData &customData );
|
||||
|
||||
bool isValidArtistData( const QString &caller, const QVariant& data, InfoCustomDataHash& customData );
|
||||
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomDataHash& customData );
|
||||
bool isValidArtistData( const QString &caller, const QVariant& data, InfoCustomData& customData );
|
||||
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomData& customData );
|
||||
Echonest::Artist artistFromReply( QNetworkReply* );
|
||||
|
||||
private slots:
|
||||
@@ -64,7 +64,7 @@ private slots:
|
||||
void getMiscTopSlot();
|
||||
|
||||
private:
|
||||
QHash< QNetworkReply*, InfoCustomDataHash > m_replyMap;
|
||||
QHash< QNetworkReply*, InfoCustomData > m_replyMap;
|
||||
QHash< QNetworkReply*, QString > m_callerMap;
|
||||
};
|
||||
|
||||
|
@@ -92,15 +92,14 @@ LastFmPlugin::~LastFmPlugin()
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData )
|
||||
LastFmPlugin::dataError( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
|
||||
{
|
||||
emit info( caller, type, data, QVariant(), customData );
|
||||
emit finished( caller, type );
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash customData )
|
||||
LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData customData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( type == InfoMiscSubmitNowPlaying )
|
||||
@@ -114,14 +113,14 @@ LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVarian
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData )
|
||||
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
|
||||
{
|
||||
if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomDataHash >() || !m_scrobbler )
|
||||
if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() || !m_scrobbler )
|
||||
{
|
||||
dataError( caller, type, data, customData );
|
||||
return;
|
||||
}
|
||||
InfoCustomDataHash hash = data.value< Tomahawk::InfoSystem::InfoCustomDataHash >();
|
||||
InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >();
|
||||
if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) )
|
||||
{
|
||||
dataError( caller, type, data, customData );
|
||||
@@ -139,11 +138,10 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar
|
||||
|
||||
m_scrobbler->nowPlaying( m_track );
|
||||
emit info( caller, type, data, QVariant(), customData );
|
||||
emit finished( caller, type );
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData )
|
||||
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
|
||||
{
|
||||
Q_ASSERT( QThread::currentThread() == thread() );
|
||||
|
||||
@@ -158,37 +156,53 @@ LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVaria
|
||||
m_scrobbler->submit();
|
||||
|
||||
emit info( caller, type, data, QVariant(), customData );
|
||||
emit finished( caller, type );
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData )
|
||||
LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomDataHash >() )
|
||||
if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() )
|
||||
{
|
||||
dataError( caller, type, data, customData );
|
||||
return;
|
||||
}
|
||||
InfoCustomDataHash hash = data.value< Tomahawk::InfoSystem::InfoCustomDataHash >();
|
||||
InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >();
|
||||
if ( !hash.contains( "artist" ) || !hash.contains( "album" ) )
|
||||
{
|
||||
dataError( caller, type, data, customData );
|
||||
return;
|
||||
}
|
||||
|
||||
QString artistName = hash["artist"].toString();
|
||||
QString albumName = hash["album"].toString();
|
||||
Tomahawk::InfoSystem::InfoCacheCriteria criteria;
|
||||
criteria["artist"] = hash["artist"].toString();
|
||||
criteria["album"] = hash["album"].toString();
|
||||
|
||||
emit getCachedInfo( criteria, caller, type, data, customData );
|
||||
}
|
||||
|
||||
void
|
||||
LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( type == InfoAlbumCoverArt )
|
||||
{
|
||||
QString artistName = criteria["artist"];
|
||||
QString albumName = criteria["album"];
|
||||
|
||||
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
|
||||
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
|
||||
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomDataHash>(customData));
|
||||
reply->setProperty("origData", data);
|
||||
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
|
||||
reply->setProperty( "origData", input );
|
||||
reply->setProperty( "caller", caller );
|
||||
reply->setProperty( "type", (uint)(type) );
|
||||
|
||||
connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
|
||||
return;
|
||||
}
|
||||
else
|
||||
qDebug() << "Couldn't figure out what to do with this type of request after cache miss";
|
||||
}
|
||||
|
||||
void
|
||||
@@ -200,17 +214,25 @@ LastFmPlugin::coverArtReturned()
|
||||
if ( redir.isEmpty() )
|
||||
{
|
||||
const QByteArray ba = reply->readAll();
|
||||
Tomahawk::InfoSystem::InfoCustomDataHash returnedData;
|
||||
InfoCustomData returnedData;
|
||||
returnedData["imgbytes"] = ba;
|
||||
returnedData["url"] = reply->url().toString();
|
||||
|
||||
InfoCustomData customData = reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
|
||||
InfoType type = (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt());
|
||||
emit info(
|
||||
reply->property( "caller" ).toString(),
|
||||
(Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt()),
|
||||
type,
|
||||
reply->property( "origData" ),
|
||||
returnedData,
|
||||
reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomDataHash >()
|
||||
customData
|
||||
);
|
||||
emit finished( reply->property( "caller" ).toString(), (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt()) );
|
||||
|
||||
InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
|
||||
Tomahawk::InfoSystem::InfoCacheCriteria criteria;
|
||||
criteria["artist"] = origData["artist"].toString();
|
||||
criteria["album"] = origData["album"].toString();
|
||||
emit updateCache( criteria, type, returnedData );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -43,19 +43,20 @@ public:
|
||||
LastFmPlugin( QObject *parent );
|
||||
virtual ~LastFmPlugin();
|
||||
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData );
|
||||
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData );
|
||||
|
||||
public slots:
|
||||
void settingsChanged();
|
||||
void onAuthenticated();
|
||||
void coverArtReturned();
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
|
||||
private:
|
||||
void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData );
|
||||
void scrobble( const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash &customData );
|
||||
void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData );
|
||||
void scrobble( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData );
|
||||
void createScrobbler();
|
||||
void nowPlaying( const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash &customData );
|
||||
void dataError( const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash &customData );
|
||||
void nowPlaying( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData );
|
||||
void dataError( const QString &caller, const InfoType type, const QVariant& data, InfoCustomData &customData );
|
||||
|
||||
lastfm::MutableTrack m_track;
|
||||
lastfm::Audioscrobbler* m_scrobbler;
|
||||
|
@@ -42,18 +42,17 @@ MusixMatchPlugin::~MusixMatchPlugin()
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void MusixMatchPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash customData)
|
||||
void MusixMatchPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData customData)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if( !isValidTrackData(caller, data, customData) || !data.canConvert<Tomahawk::InfoSystem::InfoCustomDataHash>())
|
||||
if( !isValidTrackData(caller, data, customData) || !data.canConvert<Tomahawk::InfoSystem::InfoCustomData>())
|
||||
return;
|
||||
Tomahawk::InfoSystem::InfoCustomDataHash hash = data.value<Tomahawk::InfoSystem::InfoCustomDataHash>();
|
||||
Tomahawk::InfoSystem::InfoCustomData hash = data.value<Tomahawk::InfoSystem::InfoCustomData>();
|
||||
QString artist = hash["artistName"].toString();
|
||||
QString track = hash["trackName"].toString();
|
||||
if( artist.isEmpty() || track.isEmpty() )
|
||||
{
|
||||
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
|
||||
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
return;
|
||||
}
|
||||
qDebug() << "artist is " << artist << ", track is " << track;
|
||||
@@ -63,35 +62,32 @@ void MusixMatchPlugin::getInfo(const QString &caller, const InfoType type, const
|
||||
url.addQueryItem("q_artist", artist);
|
||||
url.addQueryItem("q_track", track);
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get(QNetworkRequest(url));
|
||||
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomDataHash>(customData));
|
||||
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>(customData));
|
||||
reply->setProperty("origData", data);
|
||||
reply->setProperty("caller", caller);
|
||||
|
||||
connect(reply, SIGNAL(finished()), SLOT(trackSearchSlot()));
|
||||
}
|
||||
|
||||
bool MusixMatchPlugin::isValidTrackData(const QString &caller, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData)
|
||||
bool MusixMatchPlugin::isValidTrackData(const QString &caller, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if (data.isNull() || !data.isValid() || !data.canConvert<Tomahawk::InfoSystem::InfoCustomDataHash>())
|
||||
if (data.isNull() || !data.isValid() || !data.canConvert<Tomahawk::InfoSystem::InfoCustomData>())
|
||||
{
|
||||
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
|
||||
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
qDebug() << "MusixMatchPlugin::isValidTrackData: Data null, invalid, or can't convert";
|
||||
return false;
|
||||
}
|
||||
InfoCustomDataHash hash = data.value<Tomahawk::InfoSystem::InfoCustomDataHash>();
|
||||
InfoCustomData hash = data.value<Tomahawk::InfoSystem::InfoCustomData>();
|
||||
if (hash["trackName"].toString().isEmpty() )
|
||||
{
|
||||
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
|
||||
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
qDebug() << "MusixMatchPlugin::isValidTrackData: Track name is empty";
|
||||
return false;
|
||||
}
|
||||
if (hash["artistName"].toString().isEmpty() )
|
||||
{
|
||||
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
|
||||
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
qDebug() << "MusixMatchPlugin::isValidTrackData: No artist name found";
|
||||
return false;
|
||||
}
|
||||
@@ -104,7 +100,7 @@ void MusixMatchPlugin::trackSearchSlot()
|
||||
QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() );
|
||||
if (!oldReply)
|
||||
{
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomDataHash());
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomData());
|
||||
return;
|
||||
}
|
||||
QDomDocument doc;
|
||||
@@ -113,8 +109,7 @@ void MusixMatchPlugin::trackSearchSlot()
|
||||
QDomNodeList domNodeList = doc.elementsByTagName("track_id");
|
||||
if (domNodeList.isEmpty())
|
||||
{
|
||||
emit info(oldReply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, oldReply->property("origData"), QVariant(), oldReply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
|
||||
emit finished(oldReply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
emit info(oldReply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, oldReply->property("origData"), QVariant(), oldReply->property("customData").value<Tomahawk::InfoSystem::InfoCustomData>());
|
||||
return;
|
||||
}
|
||||
QString track_id = domNodeList.at(0).toElement().text();
|
||||
@@ -135,7 +130,7 @@ void MusixMatchPlugin::trackLyricsSlot()
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
|
||||
if (!reply)
|
||||
{
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomDataHash());
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomData());
|
||||
return;
|
||||
}
|
||||
QDomDocument doc;
|
||||
@@ -143,12 +138,10 @@ void MusixMatchPlugin::trackLyricsSlot()
|
||||
QDomNodeList domNodeList = doc.elementsByTagName("lyrics_body");
|
||||
if (domNodeList.isEmpty())
|
||||
{
|
||||
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
|
||||
emit finished(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomData>());
|
||||
return;
|
||||
}
|
||||
QString lyrics = domNodeList.at(0).toElement().text();
|
||||
qDebug() << "Emitting lyrics: " << lyrics;
|
||||
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(lyrics), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
|
||||
emit finished(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
|
||||
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(lyrics), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomData>());
|
||||
}
|
||||
|
@@ -36,10 +36,10 @@ public:
|
||||
MusixMatchPlugin(QObject *parent);
|
||||
virtual ~MusixMatchPlugin();
|
||||
|
||||
void getInfo(const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData);
|
||||
void getInfo(const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData);
|
||||
|
||||
private:
|
||||
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomDataHash &customData );
|
||||
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomData &customData );
|
||||
|
||||
public slots:
|
||||
void trackSearchSlot();
|
||||
|
@@ -25,7 +25,11 @@
|
||||
#include "infoplugins/musixmatchplugin.h"
|
||||
#include "infoplugins/lastfmplugin.h"
|
||||
|
||||
using namespace Tomahawk::InfoSystem;
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
namespace InfoSystem
|
||||
{
|
||||
|
||||
InfoPlugin::InfoPlugin(QObject *parent)
|
||||
:QObject( parent )
|
||||
@@ -33,11 +37,26 @@ InfoPlugin::InfoPlugin(QObject *parent)
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
InfoSystem *system = qobject_cast< InfoSystem* >( parent );
|
||||
if( system )
|
||||
QObject::connect( system->getCache(),
|
||||
SIGNAL( notInCache( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) ),
|
||||
{
|
||||
QObject::connect(
|
||||
this,
|
||||
SLOT( notInCacheSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash ) )
|
||||
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
system->getCache(),
|
||||
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
|
||||
);
|
||||
QObject::connect(
|
||||
system->getCache(),
|
||||
SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
this,
|
||||
SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
|
||||
);
|
||||
QObject::connect(
|
||||
this,
|
||||
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCacheCriteria, Tomahawk::InfoSystem::InfoType, QVariant ) ),
|
||||
system->getCache(),
|
||||
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria, Tomahawk::InfoSystem::InfoType, QVariant ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +65,12 @@ InfoSystem::InfoSystem(QObject *parent)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qRegisterMetaType< QMap< QString, QMap< QString, QString > > >( "Tomahawk::InfoSystem::InfoGenericMap" );
|
||||
qRegisterMetaType<QHash<QString, QVariant > >("Tomahawk::InfoSystem::InfoCustomDataHash");
|
||||
qRegisterMetaType< QHash< QString, QVariant > >( "Tomahawk::InfoSystem::InfoCustomData" );
|
||||
qRegisterMetaType< QHash< QString, QString > >( "Tomahawk::InfoSystem::InfoCacheCriteria" );
|
||||
qRegisterMetaType< Tomahawk::InfoSystem::InfoType >( "Tomahawk::InfoSystem::InfoType" );
|
||||
|
||||
m_infoSystemCacheThreadController = new QThread( this );
|
||||
m_cache = new Tomahawk::InfoSystem::InfoSystemCache();
|
||||
m_cache = new InfoSystemCache();
|
||||
m_cache->moveToThread( m_infoSystemCacheThreadController );
|
||||
m_infoSystemCacheThreadController->start( QThread::IdlePriority );
|
||||
|
||||
@@ -59,6 +80,19 @@ InfoSystem::InfoSystem(QObject *parent)
|
||||
m_plugins.append( mmptr );
|
||||
InfoPluginPtr lfmptr( new LastFmPlugin( this ) );
|
||||
m_plugins.append( lfmptr );
|
||||
|
||||
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
|
||||
{
|
||||
connect(
|
||||
plugin.data(),
|
||||
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
this,
|
||||
SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
Qt::UniqueConnection
|
||||
);
|
||||
}
|
||||
connect( m_cache, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
|
||||
this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection );
|
||||
}
|
||||
|
||||
InfoSystem::~InfoSystem()
|
||||
@@ -108,13 +142,13 @@ QLinkedList< InfoPluginPtr > InfoSystem::determineOrderedMatches(const InfoType
|
||||
return providers;
|
||||
}
|
||||
|
||||
void InfoSystem::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash customData)
|
||||
void InfoSystem::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomData customData)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
|
||||
if (providers.isEmpty())
|
||||
{
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
|
||||
emit info(QString(), InfoNoInfo, QVariant(), QVariant(), customData);
|
||||
emit finished(caller);
|
||||
return;
|
||||
}
|
||||
@@ -122,27 +156,23 @@ void InfoSystem::getInfo(const QString &caller, const InfoType type, const QVari
|
||||
InfoPluginPtr ptr = providers.first();
|
||||
if (!ptr)
|
||||
{
|
||||
emit info(QString(), Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
|
||||
emit info(QString(), InfoNoInfo, QVariant(), QVariant(), customData);
|
||||
emit finished(caller);
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataTracker[caller][type] = m_dataTracker[caller][type] + 1;
|
||||
qDebug() << "current count in dataTracker for type" << type << "is" << m_dataTracker[caller][type];
|
||||
connect(ptr.data(), SIGNAL(info(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)),
|
||||
this, SLOT(infoSlot(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)), Qt::UniqueConnection);
|
||||
connect(ptr.data(), SIGNAL(finished(QString, Tomahawk::InfoSystem::InfoType)),
|
||||
this, SLOT(finishedSlot(QString, Tomahawk::InfoSystem::InfoType)), Qt::UniqueConnection);
|
||||
ptr.data()->getInfo(caller, type, data, customData);
|
||||
}
|
||||
|
||||
void InfoSystem::getInfo(const QString &caller, const InfoMap &input, InfoCustomDataHash customData)
|
||||
void InfoSystem::getInfo(const QString &caller, const InfoMap &input, InfoCustomData customData)
|
||||
{
|
||||
Q_FOREACH( InfoType type, input.keys() )
|
||||
getInfo(caller, type, input[type], customData);
|
||||
}
|
||||
|
||||
void InfoSystem::infoSlot(QString target, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData)
|
||||
void InfoSystem::infoSlot(QString target, InfoType type, QVariant input, QVariant output, InfoCustomData customData)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];
|
||||
@@ -152,14 +182,10 @@ void InfoSystem::infoSlot(QString target, Tomahawk::InfoSystem::InfoType type, Q
|
||||
return;
|
||||
}
|
||||
emit info(target, type, input, output, customData);
|
||||
}
|
||||
|
||||
void InfoSystem::finishedSlot(QString target, Tomahawk::InfoSystem::InfoType type)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_dataTracker[target][type] = m_dataTracker[target][type] - 1;
|
||||
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];
|
||||
Q_FOREACH(Tomahawk::InfoSystem::InfoType testtype, m_dataTracker[target].keys())
|
||||
Q_FOREACH(InfoType testtype, m_dataTracker[target].keys())
|
||||
{
|
||||
if (m_dataTracker[target][testtype] != 0)
|
||||
{
|
||||
@@ -170,3 +196,7 @@ void InfoSystem::finishedSlot(QString target, Tomahawk::InfoSystem::InfoType typ
|
||||
qDebug() << "emitting finished with target" << target;
|
||||
emit finished(target);
|
||||
}
|
||||
|
||||
} //namespace InfoSystem
|
||||
|
||||
} //namespace Tomahawk
|
@@ -0,0 +1,45 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#include "infosystemcache.h"
|
||||
|
||||
void
|
||||
Tomahawk::InfoSystem::InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if( !m_memCache.contains( type ) || !m_memCache[type].contains( criteria ) )
|
||||
{
|
||||
emit notInCache( criteria, caller, type, input, customData );
|
||||
return;
|
||||
}
|
||||
|
||||
emit info( caller, type, input, m_memCache[type][criteria], customData );
|
||||
}
|
||||
|
||||
void
|
||||
Tomahawk::InfoSystem::InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, Tomahawk::InfoSystem::InfoType type, QVariant output )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QHash< InfoCacheCriteria, QVariant > typecache;
|
||||
if( m_memCache.contains( type ) )
|
||||
typecache = m_memCache[type];
|
||||
typecache[criteria] = output;
|
||||
m_memCache[type] = typecache;
|
||||
}
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include <QObject>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "tomahawk/infosystem.h"
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
@@ -44,6 +46,16 @@ public:
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
signals:
|
||||
void notInCache( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void info( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
|
||||
public slots:
|
||||
void getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
|
||||
void updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, Tomahawk::InfoSystem::InfoType type, QVariant output );
|
||||
|
||||
private:
|
||||
QHash< InfoType, QHash< InfoCacheCriteria, QVariant > > m_memCache;
|
||||
};
|
||||
|
||||
} //namespace InfoSystem
|
||||
|
@@ -146,8 +146,10 @@ set( libSources
|
||||
widgets/overlaywidget.cpp
|
||||
widgets/infowidgets/sourceinfowidget.cpp
|
||||
|
||||
qtsingleapp/qtlocalpeer.cpp
|
||||
qtsingleapp/qtsingleapplication.cpp
|
||||
kdsingleapplicationguard/kdsingleapplicationguard.cpp
|
||||
kdsingleapplicationguard/kdsharedmemorylocker.cpp
|
||||
kdsingleapplicationguard/kdtoolsglobal.cpp
|
||||
kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp
|
||||
)
|
||||
|
||||
set( libHeaders
|
||||
@@ -289,8 +291,10 @@ set( libHeaders
|
||||
widgets/overlaywidget.h
|
||||
widgets/infowidgets/sourceinfowidget.h
|
||||
|
||||
qtsingleapp/qtlocalpeer.h
|
||||
qtsingleapp/qtsingleapplication.h
|
||||
kdsingleapplicationguard/kdsingleapplicationguard.h
|
||||
kdsingleapplicationguard/kdsharedmemorylocker.h
|
||||
kdsingleapplicationguard/kdtoolsglobal.h
|
||||
kdsingleapplicationguard/kdlockedsharedmemorypointer.h
|
||||
)
|
||||
|
||||
set( libHeaders_NoMOC
|
||||
|
@@ -124,7 +124,7 @@ void
|
||||
ACLSystem::authorizePath( const QString& dbid, const QString& path, ACLSystem::ACL type )
|
||||
{
|
||||
TomahawkSettings *s = TomahawkSettings::instance();
|
||||
if( !s->scannerPath().contains( path ) )
|
||||
if( !s->scannerPaths().contains( path ) )
|
||||
{
|
||||
qDebug() << "path selected is not in our scanner path!";
|
||||
return;
|
||||
|
@@ -32,11 +32,16 @@ Database::instance()
|
||||
|
||||
Database::Database( const QString& dbname, QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_ready( false )
|
||||
, m_impl( new DatabaseImpl( dbname, this ) )
|
||||
, m_workerRW( new DatabaseWorker( m_impl, this, true ) )
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
connect( m_impl, SIGNAL( indexReady() ), SIGNAL( indexReady() ) );
|
||||
connect( m_impl, SIGNAL( indexReady() ), SIGNAL( ready() ) );
|
||||
connect( m_impl, SIGNAL( indexReady() ), SLOT( setIsReadyTrue() ) );
|
||||
|
||||
m_workerRW->start();
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,7 @@
|
||||
class DLLEXPORT Database : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Database* instance();
|
||||
|
||||
@@ -52,15 +53,23 @@ public:
|
||||
|
||||
void loadIndex();
|
||||
|
||||
bool isReady() const { return m_ready; }
|
||||
|
||||
signals:
|
||||
void indexReady(); // search index
|
||||
void ready();
|
||||
|
||||
void newJobRO( QSharedPointer<DatabaseCommand> );
|
||||
void newJobRW( QSharedPointer<DatabaseCommand> );
|
||||
|
||||
public slots:
|
||||
void enqueue( QSharedPointer<DatabaseCommand> lc );
|
||||
|
||||
private slots:
|
||||
void setIsReadyTrue() { m_ready = true; }
|
||||
|
||||
private:
|
||||
bool m_ready;
|
||||
DatabaseImpl* m_impl;
|
||||
DatabaseWorker* m_workerRW;
|
||||
QHash< QString, DatabaseWorker* > m_workers;
|
||||
|
@@ -45,6 +45,12 @@ public:
|
||||
setSource( source );
|
||||
}
|
||||
|
||||
explicit DatabaseCommand_DeleteFiles( const QVariantList& ids, const Tomahawk::source_ptr& source, QObject* parent = 0 )
|
||||
: DatabaseCommandLoggable( parent ), m_ids( ids )
|
||||
{
|
||||
setSource( source );
|
||||
}
|
||||
|
||||
virtual QString commandname() const { return "deletefiles"; }
|
||||
|
||||
virtual void exec( DatabaseImpl* );
|
||||
|
@@ -38,21 +38,35 @@ DatabaseCommand_DirMtimes::execSelect( DatabaseImpl* dbi )
|
||||
{
|
||||
QMap<QString,unsigned int> mtimes;
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
if( m_prefix.isEmpty() )
|
||||
if( m_prefix.isEmpty() && m_prefixes.isEmpty() )
|
||||
query.exec( "SELECT name, mtime FROM dirs_scanned" );
|
||||
else if( m_prefixes.isEmpty() )
|
||||
execSelectPath( dbi, m_prefix, mtimes );
|
||||
else
|
||||
{
|
||||
if( !m_prefix.isEmpty() )
|
||||
execSelectPath( dbi, m_prefix, mtimes );
|
||||
foreach( QString path, m_prefixes )
|
||||
execSelectPath( dbi, path, mtimes );
|
||||
}
|
||||
emit done( mtimes );
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseCommand_DirMtimes::execSelectPath( DatabaseImpl *dbi, const QDir& path, QMap<QString, unsigned int> &mtimes )
|
||||
{
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
query.prepare( QString( "SELECT name, mtime "
|
||||
"FROM dirs_scanned "
|
||||
"WHERE name LIKE '%1%'" ).arg( m_prefix.replace( '\'',"''" ) ) );
|
||||
"WHERE name LIKE :prefix" ) );
|
||||
|
||||
query.bindValue( ":prefix", path.absolutePath() + "%" );
|
||||
query.exec();
|
||||
}
|
||||
|
||||
while( query.next() )
|
||||
{
|
||||
mtimes.insert( query.value( 0 ).toString(), query.value( 1 ).toUInt() );
|
||||
}
|
||||
|
||||
emit done( mtimes );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -34,10 +34,14 @@ class DLLEXPORT DatabaseCommand_DirMtimes : public DatabaseCommand
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DatabaseCommand_DirMtimes( const QString& prefix = "", QObject* parent = 0 )
|
||||
explicit DatabaseCommand_DirMtimes( const QString& prefix = QString(), QObject* parent = 0 )
|
||||
: DatabaseCommand( parent ), m_prefix( prefix ), m_update( false )
|
||||
{}
|
||||
|
||||
explicit DatabaseCommand_DirMtimes( const QStringList& prefixes = QStringList(), QObject* parent = 0 )
|
||||
: DatabaseCommand( parent ), m_prefixes( prefixes ), m_update( false )
|
||||
{}
|
||||
|
||||
explicit DatabaseCommand_DirMtimes( QMap<QString, unsigned int> tosave, QObject* parent = 0 )
|
||||
: DatabaseCommand( parent ), m_update( true ), m_tosave( tosave )
|
||||
{}
|
||||
@@ -52,9 +56,12 @@ signals:
|
||||
public slots:
|
||||
|
||||
private:
|
||||
void execSelectPath( DatabaseImpl *dbi, const QDir& path, QMap<QString, unsigned int> &mtimes );
|
||||
|
||||
void execSelect( DatabaseImpl* dbi );
|
||||
void execUpdate( DatabaseImpl* dbi );
|
||||
QString m_prefix;
|
||||
QStringList m_prefixes;
|
||||
bool m_update;
|
||||
QMap<QString, unsigned int> m_tosave;
|
||||
};
|
||||
|
@@ -52,9 +52,9 @@ DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi )
|
||||
QList< QVariantMap > controls;
|
||||
QString playlist_guid;
|
||||
qDebug() << "Loading controls..." << revisionGuid();
|
||||
qDebug() << "SELECT playlist_revision.playlist, controls, plmode, pltype "
|
||||
"FROM dynamic_playlist_revision, playlist_revision "
|
||||
"WHERE dynamic_playlist_revision.guid = "<< revisionGuid() << " AND playlist_revision.guid = dynamic_playlist_revision.guid";
|
||||
// qDebug() << "SELECT playlist_revision.playlist, controls, plmode, pltype "
|
||||
// "FROM dynamic_playlist_revision, playlist_revision "
|
||||
// "WHERE dynamic_playlist_revision.guid = "<< revisionGuid() << " AND playlist_revision.guid = dynamic_playlist_revision.guid";
|
||||
if( controlsQuery.first() )
|
||||
{
|
||||
playlist_guid = controlsQuery.value( 0 ).toString();
|
||||
|
@@ -45,7 +45,7 @@ DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi )
|
||||
query_entries.bindValue( ":guid", m_revguid );
|
||||
query_entries.exec();
|
||||
|
||||
qDebug() << "trying to load entries:" << m_revguid;
|
||||
// qDebug() << "trying to load entries:" << m_revguid;
|
||||
QString prevrev;
|
||||
QJson::Parser parser; bool ok;
|
||||
|
||||
@@ -55,7 +55,6 @@ DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi )
|
||||
QVariant v = parser.parse( query_entries.value(0).toByteArray(), &ok );
|
||||
Q_ASSERT( ok && v.type() == QVariant::List ); //TODO
|
||||
m_guids = v.toStringList();
|
||||
// qDebug() << "Entries:" << guids;
|
||||
|
||||
QString inclause = QString("('%1')").arg(m_guids.join("', '"));
|
||||
|
||||
@@ -115,5 +114,5 @@ DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi )
|
||||
m_islatest = query_entries_old.value( 1 ).toBool();
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "entrymap:" << m_entrymap;
|
||||
// qDebug() << Q_FUNC_INFO << "entrymap:" << m_entrymap;
|
||||
}
|
||||
|
@@ -44,7 +44,8 @@ DatabaseCommand_LogPlayback::postCommitHook()
|
||||
connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ),
|
||||
source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
|
||||
|
||||
Tomahawk::query_ptr q = Tomahawk::Query::get( m_artist, m_track, QString(), uuid() );
|
||||
// do not auto resolve this track
|
||||
Tomahawk::query_ptr q = Tomahawk::Query::get( m_artist, m_track, QString() );
|
||||
|
||||
if ( m_action == Finished )
|
||||
{
|
||||
|
@@ -46,8 +46,6 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
||||
, m_lastalbid( 0 )
|
||||
, m_lasttrkid( 0 )
|
||||
{
|
||||
connect( this, SIGNAL( indexReady() ), parent, SIGNAL( indexReady() ) );
|
||||
|
||||
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
|
||||
db.setDatabaseName( dbname );
|
||||
if ( !db.open() )
|
||||
|
@@ -84,6 +84,8 @@ signals:
|
||||
public slots:
|
||||
|
||||
private:
|
||||
bool m_ready;
|
||||
|
||||
bool updateSchema( int currentver );
|
||||
|
||||
QSqlDatabase db;
|
||||
|
@@ -0,0 +1,475 @@
|
||||
#include "kdlockedsharedmemorypointer.h"
|
||||
|
||||
#if QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )
|
||||
#ifndef QT_NO_SHAREDMEMORY
|
||||
|
||||
namespace kdtools
|
||||
{
|
||||
}
|
||||
using namespace kdtools;
|
||||
|
||||
KDLockedSharedMemoryPointerBase::KDLockedSharedMemoryPointerBase( QSharedMemory * m )
|
||||
: locker( m ),
|
||||
mem( m )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KDLockedSharedMemoryPointerBase::KDLockedSharedMemoryPointerBase( QSharedMemory & m )
|
||||
: locker( &m ),
|
||||
mem( &m )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KDLockedSharedMemoryPointerBase::~KDLockedSharedMemoryPointerBase() {}
|
||||
|
||||
void * KDLockedSharedMemoryPointerBase::get() {
|
||||
return mem ? mem->data() : 0 ;
|
||||
}
|
||||
|
||||
const void * KDLockedSharedMemoryPointerBase::get() const {
|
||||
return mem ? mem->data() : 0 ;
|
||||
}
|
||||
|
||||
size_t KDLockedSharedMemoryPointerBase::byteSize() const {
|
||||
return mem->size();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class KDLockedSharedMemoryPointer
|
||||
\ingroup core raii smartptr
|
||||
\brief Locking pointer for Qt shared memory segments
|
||||
\since_c 2.1
|
||||
|
||||
(The exception safety of this class has not been evaluated yet.)
|
||||
|
||||
KDLockedSharedMemoryPointer is a smart immutable pointer, which gives convenient and safe access to a QSharedMemory data segment.
|
||||
The content of a KDLockedSharedMemoryPointer cannot be changed during it's lifetime.
|
||||
|
||||
You can use this class like a normal pointer to the shared memory segment and be sure it's locked while accessing it.
|
||||
\note You can only put simple types/structs/classes into it. structs and classes shall not contain any other pointers. See the
|
||||
documentation of QSharedMemory for details.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryPointer::KDLockedSharedMemoryPointer( QSharedMemory * mem )
|
||||
|
||||
Constructor. Constructs a KDLockedSharedMemory pointer which points to the data segment of \a mem.
|
||||
The constructor locks \a mem. If the memory segment is already locked by another process, this constructor
|
||||
blocks until the lock is released.
|
||||
|
||||
\post data() == mem->data() and the memory segment has been locked
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryPointer::KDLockedSharedMemoryPointer( QSharedMemory & mem )
|
||||
|
||||
\overload
|
||||
|
||||
\post data() == mem.data() and the memory segment has been locked
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryPointer::~KDLockedSharedMemoryPointer()
|
||||
|
||||
Destructor. Unlocks the shared memory segment.
|
||||
|
||||
\post The shared memory segment has been unlocked
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T * KDLockedSharedMemoryPointer::get()
|
||||
|
||||
\returns a pointer to the contained object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T * KDLockedSharedMemoryPointer::get() const
|
||||
|
||||
\returns a const pointer to the contained object
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T * KDLockedSharedMemoryPointer::data()
|
||||
|
||||
Equivalent to get(), provided for consistency with Qt naming conventions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T * KDLockedSharedMemoryPointer::data() const
|
||||
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T & KDLockedSharedMemoryPointer::operator*()
|
||||
|
||||
Dereference operator. Returns \link get() *get()\endlink.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T & KDLockedSharedMemoryPointer::operator*() const
|
||||
|
||||
Dereference operator. Returns \link get() *get()\endlink.
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T * KDLockedSharedMemoryPointer::operator->()
|
||||
|
||||
Member-by-pointer operator. Returns get().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T * KDLockedSharedMemoryPointer::operator->() const
|
||||
|
||||
Member-by-pointer operator. Returns get().
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class KDLockedSharedMemoryArray
|
||||
\ingroup core raii smartptr
|
||||
\brief Locking array pointer to Qt shared memory segments
|
||||
\since_c 2.1
|
||||
|
||||
(The exception safety of this class has not been evaluated yet.)
|
||||
|
||||
KDLockedSharedMemoryArray is a smart immutable pointer, which gives convenient and safe access to array data stored in a QSharedMemory
|
||||
data segment.
|
||||
The content of a KDLockedSharedMemoryArray cannot be changed during it's lifetime.
|
||||
|
||||
You can use this class like a normal pointer to the shared memory segment and be sure it's locked while accessing it.
|
||||
\note You can only put arrays of simple types/structs/classes into it. structs and classes shall not contain any other pointers. See the
|
||||
documentation of QSharedMemory for details.
|
||||
|
||||
\sa KDLockedSharedMemoryPointer
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::KDLockedSharedMemoryArray( QSharedMemory* mem )
|
||||
Constructor. Constructs a KDLockedSharedMemoryArray which points to the data segment of \a mem. The constructor locks \a mem. If the memory
|
||||
segment is already locked by another process, this constructor blocks until the lock is release.
|
||||
|
||||
\post get() == mem->data() and the memory segment has been locked
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::KDLockedSharedMemoryArray( QSharedMemory& mem )
|
||||
\overload
|
||||
|
||||
\post get() == mem->data() and the memory segment has been locked
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::size_type
|
||||
Typedef for std::size_t. Provided for STL compatibility.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::difference_type
|
||||
Typedef for std::ptrdiff_t. Provided for STL compatibility.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::iterator
|
||||
Typedef for T*. Provided for STL compatibility.
|
||||
\since_t 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::const_iterator
|
||||
Typedef for const T*. Provided for STL compatibility.
|
||||
\since_t 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::reverse_iterator
|
||||
Typedef for std::reverse_iterator< \link KDLockedSharedMemoryArray::iterator iterator\endlink >. Provided for STL compatibility.
|
||||
\since_t 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef KDLockedSharedMemoryArray::const_reverse_iterator
|
||||
Typedef for std::reverse_iterator< \link KDLockedSharedMemoryArray::const_iterator const_iterator\endlink >. Provided for STL compatibility.
|
||||
\since_t 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::iterator KDLockedSharedMemoryArray::begin()
|
||||
Returns an \link KDLockedSharedMemoryArray::iterator iterator\endlink pointing to the first item of the array.
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::const_iterator KDLockedSharedMemoryArray::begin() const
|
||||
\overload
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::iterator KDLockedSharedMemoryArray::end()
|
||||
Returns an \link KDLockedSharedMemoryArray::iterator iterator\endlink pointing to the item after the last item of the array.
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::const_iterator KDLockedSharedMemoryArray::end() const
|
||||
\overload
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::reverse_iterator KDLockedSharedMemoryArray::rbegin()
|
||||
Returns an \link KDLockedSharedMemoryArray::reverse_iterator reverse_iterator\endlink pointing to the item after the last item of the array.
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::const_reverse_iterator KDLockedSharedMemoryArray::rbegin() const
|
||||
\overload
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::reverse_iterator KDLockedSharedMemoryArray::rend()
|
||||
Returns an \link KDLockedSharedMemoryArray::reverse_iterator reverse_iterator\endlink pointing to the first item of the array.
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::const_reverse_iterator KDLockedSharedMemoryArray::rend() const
|
||||
\overload
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn KDLockedSharedMemoryArray::size_type KDLockedSharedMemoryArray::size() const
|
||||
Returns the size of this array. The size is calculated from the storage size of T and
|
||||
the size of the shared memory segment.
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T& KDLockedSharedMemoryArray::operator[]( difference_type n )
|
||||
Array access operator. Returns a reference to the item at index position \a n.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T& KDLockedSharedMemoryArray::operator[]( difference_type n ) const
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T& KDLockedSharedMemoryArray::front()
|
||||
Returns a reference to the first item in the array. This is the same as operator[](0).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T& KDLockedSharedMemoryArray::front() const
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T& KDLockedSharedMemoryArray::back()
|
||||
Returns a reference to the last item in the array. This is the same as operator[](size()-1).
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T& KDLockedSharedMemoryArray::back() const
|
||||
\overload
|
||||
\since_f 2.2
|
||||
*/
|
||||
|
||||
|
||||
#ifdef eKDTOOLSCORE_UNITTESTS
|
||||
|
||||
#include <KDUnitTest/Test>
|
||||
|
||||
#include <QThread>
|
||||
#include <QUuid>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TestStruct
|
||||
{
|
||||
TestStruct( uint nn = 0 )
|
||||
: n( nn ),
|
||||
f( 0.0 ),
|
||||
c( '\0' ),
|
||||
b( false )
|
||||
{
|
||||
}
|
||||
uint n;
|
||||
double f;
|
||||
char c;
|
||||
bool b;
|
||||
};
|
||||
|
||||
bool operator==( const TestStruct& lhs, const TestStruct& rhs )
|
||||
{
|
||||
return lhs.n == rhs.n && lhs.f == rhs.f && lhs.c == rhs.c && lhs.b == rhs.b;
|
||||
}
|
||||
|
||||
class TestThread : public QThread
|
||||
{
|
||||
public:
|
||||
TestThread( const QString& key )
|
||||
: mem( key )
|
||||
{
|
||||
mem.attach();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
msleep( 100 );
|
||||
kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
|
||||
if( !p->b )
|
||||
continue;
|
||||
|
||||
p->n = 5;
|
||||
p->f = 3.14;
|
||||
p->c = 'A';
|
||||
p->b = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QSharedMemory mem;
|
||||
};
|
||||
|
||||
bool isConst( TestStruct* )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isConst( const TestStruct* )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
KDAB_UNITTEST_SIMPLE( KDLockedSharedMemoryPointer, "kdcoretools" ) {
|
||||
|
||||
const QString key = QUuid::createUuid();
|
||||
QSharedMemory mem( key );
|
||||
const bool created = mem.create( sizeof( TestStruct ) );
|
||||
assertTrue( created );
|
||||
if ( !created )
|
||||
return; // don't execute tests if shm coulnd't be created
|
||||
|
||||
// On Windows, shared mem is only available in increments of page
|
||||
// size (4k), so don't fail if the segment is larger:
|
||||
const unsigned long mem_size = mem.size();
|
||||
assertGreaterOrEqual( mem_size, sizeof( TestStruct ) );
|
||||
|
||||
{
|
||||
kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
|
||||
assertTrue( p );
|
||||
*p = TestStruct();
|
||||
assertEqual( p->n, 0u );
|
||||
assertEqual( p->f, 0.0 );
|
||||
assertEqual( p->c, '\0' );
|
||||
assertFalse( p->b );
|
||||
}
|
||||
|
||||
{
|
||||
TestThread thread( key );
|
||||
assertEqual( thread.mem.key().toStdString(), key.toStdString() );
|
||||
assertEqual( static_cast< unsigned long >( thread.mem.size() ), mem_size );
|
||||
thread.start();
|
||||
|
||||
assertTrue( thread.isRunning() );
|
||||
thread.wait( 2000 );
|
||||
assertTrue( thread.isRunning() );
|
||||
|
||||
{
|
||||
kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
|
||||
p->b = true;
|
||||
}
|
||||
|
||||
thread.wait( 2000 );
|
||||
assertFalse( thread.isRunning() );
|
||||
}
|
||||
|
||||
{
|
||||
kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
|
||||
assertEqual( p->n, 5u );
|
||||
assertEqual( p->f, 3.14 );
|
||||
assertEqual( p->c, 'A' );
|
||||
assertFalse( p->b );
|
||||
}
|
||||
|
||||
{
|
||||
kdtools::KDLockedSharedMemoryPointer< TestStruct > p( mem );
|
||||
assertEqual( mem.data(), p.get() );
|
||||
assertEqual( p.get(), p.operator->() );
|
||||
assertEqual( p.get(), &(*p) );
|
||||
assertEqual( p.get(), p.data() );
|
||||
assertFalse( isConst( p.get() ) );
|
||||
}
|
||||
|
||||
{
|
||||
const kdtools::KDLockedSharedMemoryPointer< TestStruct > p( &mem );
|
||||
assertEqual( mem.data(), p.get() );
|
||||
assertEqual( p.get(), p.operator->() );
|
||||
assertEqual( p.get(), &(*p) );
|
||||
assertEqual( p.get(), p.data() );
|
||||
assertTrue( isConst( p.get() ) );
|
||||
}
|
||||
|
||||
{
|
||||
QSharedMemory mem2( key + key );
|
||||
const bool created2 = mem2.create( 16 * sizeof( TestStruct ) );
|
||||
assertTrue( created2 );
|
||||
if ( !created2 )
|
||||
return; // don't execute tests if shm coulnd't be created
|
||||
|
||||
kdtools::KDLockedSharedMemoryArray<TestStruct> a( mem2 );
|
||||
assertTrue( a );
|
||||
assertEqual( a.get(), mem2.data() );
|
||||
assertEqual( &a[0], a.get() );
|
||||
|
||||
a[1] = a[0];
|
||||
assertTrue( a[0] == a[1] );
|
||||
|
||||
TestStruct ts;
|
||||
ts.n = 5;
|
||||
ts.f = 3.14;
|
||||
a[0] = ts;
|
||||
assertFalse( a[0] == a[1] );
|
||||
assertEqual( a.front().n, ts.n );
|
||||
assertEqual( a[0].f, ts.f );
|
||||
a[0].n = 10;
|
||||
assertEqual( a.front().n, 10u );
|
||||
ts = a[0];
|
||||
assertEqual( ts.n, 10u );
|
||||
|
||||
std::vector< TestStruct > v;
|
||||
for( uint i = 0; i < a.size(); ++i )
|
||||
v.push_back( TestStruct( i ) );
|
||||
|
||||
std::copy( v.begin(), v.end(), a.begin() );
|
||||
for( uint i = 0; i < a.size(); ++i )
|
||||
assertEqual( a[ i ].n, i );
|
||||
assertEqual( a.front().n, 0u );
|
||||
assertEqual( a.back().n, a.size() - 1 );
|
||||
|
||||
std::copy( v.begin(), v.end(), a.rbegin() );
|
||||
for( uint i = 0; i < a.size(); ++i )
|
||||
assertEqual( a[ i ].n, a.size() - 1 - i );
|
||||
assertEqual( a.front().n, a.size() - 1 );
|
||||
assertEqual( a.back().n, 0u );
|
||||
}
|
||||
|
||||
}
|
||||
#endif // KDTOOLSCORE_UNITTESTS
|
||||
#endif // QT_NO_SHAREDMEMORY
|
||||
#endif // QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )
|
@@ -0,0 +1,115 @@
|
||||
#ifndef __KDTOOLS__CORE__KDLOCKEDSHAREDMEMORYPOINTER_H__
|
||||
#define __KDTOOLS__CORE__KDLOCKEDSHAREDMEMORYPOINTER_H__
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )
|
||||
#ifndef QT_NO_SHAREDMEMORY
|
||||
|
||||
#include "kdsharedmemorylocker.h"
|
||||
#include <QtCore/QSharedMemory>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
namespace kdtools {
|
||||
#endif
|
||||
|
||||
class KDLockedSharedMemoryPointerBase {
|
||||
protected:
|
||||
explicit KDLockedSharedMemoryPointerBase( QSharedMemory * mem );
|
||||
explicit KDLockedSharedMemoryPointerBase( QSharedMemory & mem );
|
||||
~KDLockedSharedMemoryPointerBase();
|
||||
|
||||
// PENDING(marc) do we really want const propagation here? I
|
||||
// usually declare all my RAII objects const...
|
||||
void * get();
|
||||
const void * get() const;
|
||||
|
||||
KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( get() )
|
||||
|
||||
size_t byteSize() const;
|
||||
|
||||
private:
|
||||
KDSharedMemoryLocker locker;
|
||||
QSharedMemory * const mem;
|
||||
};
|
||||
|
||||
template< typename T>
|
||||
class MAKEINCLUDES_EXPORT KDLockedSharedMemoryPointer : KDLockedSharedMemoryPointerBase {
|
||||
KDAB_DISABLE_COPY( KDLockedSharedMemoryPointer );
|
||||
public:
|
||||
explicit KDLockedSharedMemoryPointer( QSharedMemory * m )
|
||||
: KDLockedSharedMemoryPointerBase( m ) {}
|
||||
explicit KDLockedSharedMemoryPointer( QSharedMemory & m )
|
||||
: KDLockedSharedMemoryPointerBase( m ) {}
|
||||
|
||||
T * get() { return static_cast<T*>( KDLockedSharedMemoryPointerBase::get() ); }
|
||||
const T * get() const { return static_cast<const T*>( KDLockedSharedMemoryPointerBase::get() ); }
|
||||
|
||||
T * data() { return static_cast<T*>( get() ); }
|
||||
const T * data() const { return static_cast<const T*>( get() ); }
|
||||
|
||||
T & operator*() { assert( get() ); return *get(); }
|
||||
const T & operator*() const { assert( get() ); return *get(); }
|
||||
|
||||
T * operator->() { return get(); }
|
||||
const T * operator->() const { return get(); }
|
||||
|
||||
KDAB_USING_SAFE_BOOL_OPERATOR( KDLockedSharedMemoryPointerBase )
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MAKEINCLUDES_EXPORT KDLockedSharedMemoryArray : KDLockedSharedMemoryPointerBase {
|
||||
KDAB_DISABLE_COPY( KDLockedSharedMemoryArray );
|
||||
public:
|
||||
explicit KDLockedSharedMemoryArray( QSharedMemory * m )
|
||||
: KDLockedSharedMemoryPointerBase( m ) {}
|
||||
explicit KDLockedSharedMemoryArray( QSharedMemory & m )
|
||||
: KDLockedSharedMemoryPointerBase( m ) {}
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
|
||||
typedef std::reverse_iterator< iterator > reverse_iterator;
|
||||
|
||||
iterator begin() { return get(); }
|
||||
const_iterator begin() const { return get(); }
|
||||
|
||||
iterator end() { return begin() + size(); }
|
||||
const_iterator end() const { return begin() + size(); }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator( end() ); }
|
||||
const_reverse_iterator rbegin() const { return reverse_iterator( end() ); }
|
||||
|
||||
reverse_iterator rend() { return reverse_iterator( begin() ); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator( begin() ); }
|
||||
|
||||
size_type size() const { return byteSize() / sizeof( T ); }
|
||||
|
||||
T * get() { return static_cast<T*>( KDLockedSharedMemoryPointerBase::get() ); }
|
||||
const T * get() const { return static_cast<const T*>( KDLockedSharedMemoryPointerBase::get() ); }
|
||||
|
||||
T & operator[]( difference_type n ) { assert( get() ); return *(get()+n); }
|
||||
const T & operator[]( difference_type n ) const { assert( get() ); return *(get()+n); }
|
||||
|
||||
T & front() { assert( get() ); return *get(); }
|
||||
const T & front() const { assert( get() ); return *get(); }
|
||||
|
||||
T & back() { assert( get() ); return *( get() + size() - 1 ); }
|
||||
const T & back() const { assert( get() ); return *( get() + size() - 1 ); }
|
||||
|
||||
KDAB_USING_SAFE_BOOL_OPERATOR( KDLockedSharedMemoryPointerBase )
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* QT_NO_SHAREDMEMORY */
|
||||
|
||||
#endif /* QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN ) */
|
||||
|
||||
#endif /* __KDTOOLS__CORE__KDLOCKEDSHAREDMEMORYPOINTER_H__ */
|
@@ -0,0 +1,40 @@
|
||||
#include "kdsharedmemorylocker.h"
|
||||
|
||||
#if QT_VERSION >= 0x040400 || defined( DOXYGEN_RUN )
|
||||
|
||||
#include <QSharedMemory>
|
||||
|
||||
using namespace kdtools;
|
||||
|
||||
/*!
|
||||
\class KDSharedMemoryLocker
|
||||
\ingroup raii core
|
||||
\brief Exception-safe and convenient wrapper around QSharedMemory::lock()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor. Locks the shared memory segment \a mem.
|
||||
* If another process has locking the segment, this constructor blocks
|
||||
* until the lock is released. The memory segments needs to be properly created or attached.
|
||||
*/
|
||||
KDSharedMemoryLocker::KDSharedMemoryLocker( QSharedMemory* mem )
|
||||
: mem( mem )
|
||||
{
|
||||
mem->lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor. Unlocks the shared memory segment associated with this
|
||||
* KDSharedMemoryLocker.
|
||||
*/
|
||||
KDSharedMemoryLocker::~KDSharedMemoryLocker()
|
||||
{
|
||||
mem->unlock();
|
||||
}
|
||||
|
||||
#ifdef KDAB_EVAL
|
||||
#include KDAB_EVAL
|
||||
static const EvalDialogChecker evalChecker( "KD Tools", false );
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -0,0 +1,36 @@
|
||||
#ifndef __KDTOOLS__CORE__KDSHAREDMEMORYLOCKER_H
|
||||
#define __KDTOOLS__CORE__KDSHAREDMEMORYLOCKER_H
|
||||
|
||||
#include "kdtoolsglobal.h"
|
||||
|
||||
#if QT_VERSION < 0x040400 && !defined( DOXYGEN_RUN )
|
||||
#ifdef Q_CC_GNU
|
||||
#warning "Can't use KDTools KDSharedMemoryLocker with Qt versions prior to 4.4"
|
||||
#endif
|
||||
#else
|
||||
|
||||
class QSharedMemory;
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
namespace kdtools
|
||||
{
|
||||
#endif
|
||||
|
||||
class KDTOOLSCORE_EXPORT KDSharedMemoryLocker
|
||||
{
|
||||
Q_DISABLE_COPY( KDSharedMemoryLocker )
|
||||
public:
|
||||
KDSharedMemoryLocker( QSharedMemory* mem );
|
||||
~KDSharedMemoryLocker();
|
||||
|
||||
private:
|
||||
QSharedMemory* const mem;
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -0,0 +1,622 @@
|
||||
#include "kdsingleapplicationguard.h"
|
||||
|
||||
#ifndef KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES
|
||||
#define KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES 128
|
||||
#endif
|
||||
|
||||
#ifndef KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE
|
||||
#define KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE 1024
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
KDSingleApplicationGuard::Instance::Instance( const QStringList& args, qint64 p )
|
||||
: arguments( args ),
|
||||
pid( p )
|
||||
{
|
||||
}
|
||||
|
||||
#if QT_VERSION < 0x040400
|
||||
|
||||
class KDSingleApplicationGuard::Private
|
||||
{
|
||||
};
|
||||
|
||||
KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication*, Policy )
|
||||
{
|
||||
qWarning( "KD Tools was compiled with a Qt version prior to 4.4. SingleApplicationGuard won't work." );
|
||||
}
|
||||
|
||||
KDSingleApplicationGuard::~KDSingleApplicationGuard()
|
||||
{
|
||||
}
|
||||
|
||||
void KDSingleApplicationGuard::shutdownOtherInstances()
|
||||
{
|
||||
}
|
||||
|
||||
void KDSingleApplicationGuard::killOtherInstances()
|
||||
{
|
||||
}
|
||||
|
||||
void KDSingleApplicationGuard::timerEvent( QTimerEvent* )
|
||||
{
|
||||
}
|
||||
#else
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QSharedMemory>
|
||||
|
||||
#include "kdsharedmemorylocker.h"
|
||||
#include "kdlockedsharedmemorypointer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
using namespace kdtools;
|
||||
|
||||
/*!
|
||||
\class KDSingleApplicationGuard KDSingleApplicationGuard
|
||||
\brief A guard to protect an application from having several instances.
|
||||
|
||||
KDSingleApplicationGuard can be used to make sure only one instance of an
|
||||
application is running at the same time.
|
||||
|
||||
\note As KDSingleApplicationGuard uses QSharedMemory Qt 4.4 or later is required
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void KDSingleApplicationGuard::instanceStarted()
|
||||
This signal is emitted by the primary instance when ever one other
|
||||
instance was started.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void KDSingleApplicationGuard::instanceExited()
|
||||
This signal is emitted by the primary instance when ever one other
|
||||
instance was exited.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void KDSingleApplicationGuard::becamePrimaryInstance()
|
||||
This signal is emitted, when the current running application gets the new
|
||||
primary application. The old primary application has quit.
|
||||
*/
|
||||
|
||||
enum Command
|
||||
{
|
||||
NoCommand = 0x00,
|
||||
ExitedInstance = 0x01,
|
||||
NewInstance = 0x02,
|
||||
FreeInstance = 0x04,
|
||||
ShutDownCommand = 0x08,
|
||||
KillCommand = 0x10,
|
||||
BecomePrimaryCommand = 0x20
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS( Commands, Command )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( Commands )
|
||||
|
||||
struct ProcessInfo
|
||||
{
|
||||
explicit ProcessInfo( Command c = FreeInstance, const QStringList& arguments = QStringList(), qint64 p = -1 )
|
||||
: command( c ),
|
||||
pid( p )
|
||||
{
|
||||
std::fill_n( commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE, '\0' );
|
||||
|
||||
int argpos = 0;
|
||||
for( QStringList::const_iterator it = arguments.begin(); it != arguments.end(); ++it )
|
||||
{
|
||||
const QByteArray arg = it->toLatin1();
|
||||
const int count = qMin( KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE - argpos, arg.count() );
|
||||
std::copy( arg.begin(), arg.begin() + count, commandline + argpos );
|
||||
argpos += arg.count() + 1; // makes sure there's a \0 between every parameter
|
||||
}
|
||||
}
|
||||
|
||||
QStringList arguments() const
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
QByteArray arg;
|
||||
for( int i = 0; i < KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE; ++i )
|
||||
{
|
||||
if( commandline[ i ] == '\0' && !arg.isEmpty() )
|
||||
{
|
||||
result.push_back( QString::fromLatin1( arg ) );
|
||||
arg.clear();
|
||||
}
|
||||
else if( !commandline[ i ] == '\0' )
|
||||
{
|
||||
arg.push_back( commandline[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Commands command;
|
||||
char commandline[ KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE ];
|
||||
qint64 pid;
|
||||
};
|
||||
|
||||
bool operator==( const ProcessInfo& lhs, const ProcessInfo& rhs )
|
||||
{
|
||||
return lhs.command == rhs.command &&
|
||||
::memcmp( lhs.commandline, rhs.commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE ) == 0;
|
||||
}
|
||||
|
||||
bool operator!=( const ProcessInfo& lhs, const ProcessInfo& rhs )
|
||||
{
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
/*!
|
||||
This struct contains information about the managed process system.
|
||||
\internal
|
||||
*/
|
||||
struct InstanceRegister
|
||||
{
|
||||
InstanceRegister( KDSingleApplicationGuard::Policy policy = KDSingleApplicationGuard::NoPolicy )
|
||||
: policy( policy )
|
||||
{
|
||||
std::fill_n( info, KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() );
|
||||
::memcpy( magicCookie, "kdsingleapp", 12 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns wheter this register was properly initialized by the first instance.
|
||||
*/
|
||||
bool isValid() const
|
||||
{
|
||||
return ::strcmp( magicCookie, "kdsingleapp" ) == 0;
|
||||
}
|
||||
|
||||
ProcessInfo info[ KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES ];
|
||||
KDSingleApplicationGuard::Policy policy;
|
||||
char magicCookie[ 12 ];
|
||||
};
|
||||
|
||||
bool operator==( const InstanceRegister& lhs, const InstanceRegister& rhs )
|
||||
{
|
||||
if( lhs.policy != rhs.policy )
|
||||
return false;
|
||||
|
||||
for( int i = 0; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
if( lhs.info[ i ] != rhs.info[ i ] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
class KDSingleApplicationGuard::Private
|
||||
{
|
||||
public:
|
||||
Private( KDSingleApplicationGuard* qq )
|
||||
: q( qq ),
|
||||
id( -1 )
|
||||
{
|
||||
if( primaryInstance == 0 )
|
||||
primaryInstance = q;
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
if( primaryInstance == q )
|
||||
primaryInstance = 0;
|
||||
}
|
||||
|
||||
void shutdownInstance()
|
||||
{
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &q->d->mem );
|
||||
instances->info[ q->d->id ].command = ExitedInstance;
|
||||
|
||||
if( q->isPrimaryInstance() )
|
||||
{
|
||||
// ohh... we need a new primary instance...
|
||||
for( int i = 1; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
{
|
||||
if( ( instances->info[ i ].command & ( FreeInstance | ExitedInstance | ShutDownCommand | KillCommand ) ) == 0 )
|
||||
{
|
||||
instances->info[ i ].command |= BecomePrimaryCommand;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// none found? then my species is dead :-(
|
||||
}
|
||||
}
|
||||
|
||||
static KDSingleApplicationGuard* primaryInstance;
|
||||
|
||||
private:
|
||||
KDSingleApplicationGuard* const q;
|
||||
|
||||
public:
|
||||
Policy policy;
|
||||
QSharedMemory mem;
|
||||
int id;
|
||||
};
|
||||
|
||||
KDSingleApplicationGuard* KDSingleApplicationGuard::Private::primaryInstance = 0;
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
void SIGINT_handler( int sig )
|
||||
{
|
||||
if( sig == SIGINT && KDSingleApplicationGuard::Private::primaryInstance != 0 )
|
||||
KDSingleApplicationGuard::Private::primaryInstance->d->shutdownInstance();
|
||||
::exit( 1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Creates a new KDSingleApplicationGuard guarding \a parent from mulitply instances.
|
||||
If \a policy is AutoKillOtherInstances (the default), all instances, which try to start,
|
||||
are killed automatically and instanceStarted() is emitted.
|
||||
If \a policy is NoPolicy, the other instance will run and instanceStarted() is emitted.
|
||||
*/
|
||||
KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication* parent, Policy policy )
|
||||
: QObject( parent ),
|
||||
d( new Private( this ) )
|
||||
{
|
||||
const QString name = parent->applicationName();
|
||||
Q_ASSERT_X( !name.isEmpty(), "KDSingleApplicationGuard::KDSingleApplicationGuard", "applicationName must not be emty" );
|
||||
d->mem.setKey( name );
|
||||
|
||||
// if another instance crashed, the shared memory segment is still there on Unix
|
||||
// the following lines trigger deletion in that case
|
||||
#ifndef Q_WS_WIN
|
||||
d->mem.attach();
|
||||
d->mem.detach();
|
||||
#endif
|
||||
|
||||
d->policy = policy;
|
||||
|
||||
const bool created = d->mem.create( sizeof( InstanceRegister ) );
|
||||
if( !created )
|
||||
{
|
||||
if( !d->mem.attach() )
|
||||
{
|
||||
qWarning( "KDSingleApplicationGuard: Could neither create nor attach to shared memory segment." );
|
||||
return;
|
||||
}
|
||||
|
||||
// lets wait till the other instance initialized the register
|
||||
bool initialized = false;
|
||||
while( !initialized )
|
||||
{
|
||||
const KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
initialized = instances->isValid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
|
||||
if( !created )
|
||||
{
|
||||
// we're _not_ the first instance
|
||||
// but the
|
||||
bool killOurSelf = false;
|
||||
|
||||
// find a new slot...
|
||||
d->id = std::find( instances->info, instances->info + KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() ) - instances->info;
|
||||
ProcessInfo& info = instances->info[ d->id ];
|
||||
info = ProcessInfo( NewInstance, parent->arguments(), QCoreApplication::applicationPid() );
|
||||
killOurSelf = instances->policy == AutoKillOtherInstances;
|
||||
d->policy = instances->policy;
|
||||
|
||||
// but the signal that we tried to start was sent to the primary application
|
||||
if( killOurSelf )
|
||||
{
|
||||
info.command |= ExitedInstance;
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ok.... we are the first instance
|
||||
InstanceRegister reg( policy ); // create a new list
|
||||
d->id = 0; // our id = 0
|
||||
// and we've no command
|
||||
reg.info[ 0 ] = ProcessInfo( NoCommand, parent->arguments(), QCoreApplication::applicationPid() );
|
||||
*instances = reg; // push this is the process list into shared memory
|
||||
}
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
::signal( SIGINT, SIGINT_handler );
|
||||
#endif
|
||||
|
||||
// now listen for commands
|
||||
startTimer( 250 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys this SingleApplicationGuard.
|
||||
If this instance has been the primary instance and no other instance is existing anymore,
|
||||
the application is shut down completely. Otherwise the destructor selects another instance to
|
||||
be the primary instances.
|
||||
*/
|
||||
KDSingleApplicationGuard::~KDSingleApplicationGuard()
|
||||
{
|
||||
if( d->id == -1 )
|
||||
return;
|
||||
|
||||
d->shutdownInstance();
|
||||
}
|
||||
|
||||
/*!
|
||||
\property KDSingleApplicationGuard::primaryInstance
|
||||
Determines wheter this instance is the primary instance.
|
||||
The primary instance is the first instance which was started or an instance which
|
||||
got selected by KDSingleApplicationGuard's destructor, when the primary instance was
|
||||
shut down.
|
||||
|
||||
Get this property's value using %isPrimaryInstance(), and monitor changes to it
|
||||
using becamePrimaryInstance().
|
||||
*/
|
||||
bool KDSingleApplicationGuard::isPrimaryInstance() const
|
||||
{
|
||||
return d->id == 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property KDSingleApplicationGuard::Policy
|
||||
Specifies the policy KDSingleApplicationGuard is using when new instances are started.
|
||||
This can only be set in the primary instance.
|
||||
|
||||
Get this property's value using %policy(), set it using %setPolicy(), and monitor changes
|
||||
to it using policyChanged().
|
||||
*/
|
||||
KDSingleApplicationGuard::Policy KDSingleApplicationGuard::policy() const
|
||||
{
|
||||
return d->policy;
|
||||
}
|
||||
|
||||
void KDSingleApplicationGuard::setPolicy( Policy policy )
|
||||
{
|
||||
Q_ASSERT( isPrimaryInstance() );
|
||||
if( d->policy == policy )
|
||||
return;
|
||||
|
||||
d->policy = policy;
|
||||
emit policyChanged();
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
instances->policy = policy;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a list of all currently running instances.
|
||||
*/
|
||||
QList< KDSingleApplicationGuard::Instance > KDSingleApplicationGuard::instances() const
|
||||
{
|
||||
QList< Instance > result;
|
||||
const KDLockedSharedMemoryPointer< InstanceRegister > instances( const_cast< QSharedMemory* >( &d->mem ) );
|
||||
for( int i = 0; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
{
|
||||
const ProcessInfo& info = instances->info[ i ];
|
||||
if( ( info.command & ( FreeInstance | ExitedInstance ) ) == 0 )
|
||||
result.push_back( Instance( info.arguments(), info.pid ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
Shuts down all other instances. This can only be called from the
|
||||
the primary instance.
|
||||
Shut down is done gracefully via QCoreApplication::quit().
|
||||
*/
|
||||
void KDSingleApplicationGuard::shutdownOtherInstances()
|
||||
{
|
||||
Q_ASSERT( isPrimaryInstance() );
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
for( int i = 1; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
{
|
||||
if( ( instances->info[ i ].command & ( FreeInstance | ExitedInstance ) ) == 0 )
|
||||
instances->info[ i ].command = ShutDownCommand;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Kills all other instances. This can only be called from the
|
||||
the primary instance.
|
||||
Killing is done via exit(1)
|
||||
*/
|
||||
void KDSingleApplicationGuard::killOtherInstances()
|
||||
{
|
||||
Q_ASSERT( isPrimaryInstance() );
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
for( int i = 1; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
{
|
||||
if( ( instances->info[ i ].command & ( FreeInstance | ExitedInstance ) ) == 0 )
|
||||
instances->info[ i ].command = KillCommand;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\reimp
|
||||
*/
|
||||
void KDSingleApplicationGuard::timerEvent( QTimerEvent* event )
|
||||
{
|
||||
Q_UNUSED( event )
|
||||
|
||||
if( isPrimaryInstance() )
|
||||
{
|
||||
// only the primary instance will get notified about new instances
|
||||
QList< Instance > exitedInstances;
|
||||
QList< Instance > startedInstances;
|
||||
|
||||
{
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
|
||||
for( int i = 1; i < KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES; ++i )
|
||||
{
|
||||
ProcessInfo& info = instances->info[ i ];
|
||||
if( info.command & NewInstance )
|
||||
{
|
||||
startedInstances.push_back( Instance( info.arguments(), info.pid ) );
|
||||
info.command &= ~NewInstance; // clear NewInstance flag
|
||||
}
|
||||
else if( info.command & ExitedInstance )
|
||||
{
|
||||
exitedInstances.push_back( Instance( info.arguments(), info.pid ) );
|
||||
info.command = FreeInstance; // set FreeInstance flag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// one signal for every new instance - _after_ the memory segment was unlocked again
|
||||
for( QList< Instance >::const_iterator it = startedInstances.begin(); it != startedInstances.end(); ++it )
|
||||
emit instanceStarted( *it );
|
||||
for( QList< Instance >::const_iterator it = exitedInstances.begin(); it != exitedInstances.end(); ++it )
|
||||
emit instanceExited( *it );
|
||||
}
|
||||
else
|
||||
{
|
||||
// do we have a command?
|
||||
bool killOurSelf = false;
|
||||
bool shutDownOurSelf = false;
|
||||
bool policyDidChange = false;
|
||||
|
||||
{
|
||||
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
|
||||
|
||||
policyDidChange = instances->policy != d->policy;
|
||||
d->policy = instances->policy;
|
||||
|
||||
if( instances->info[ d->id ].command & BecomePrimaryCommand )
|
||||
{
|
||||
// we became primary!
|
||||
instances->info[ 0 ] = instances->info[ d->id ];
|
||||
instances->info[ d->id ] = ProcessInfo(); // change our id to 0 and declare the old slot as free
|
||||
d->id = 0;
|
||||
emit becamePrimaryInstance();
|
||||
}
|
||||
|
||||
killOurSelf = instances->info[ d->id ].command & KillCommand; // check for kill command
|
||||
shutDownOurSelf = instances->info[ d->id ].command & ShutDownCommand; // check for shut down command
|
||||
instances->info[ d->id ].command &= ~( KillCommand | ShutDownCommand | BecomePrimaryCommand ); // reset both flags
|
||||
if( killOurSelf )
|
||||
{
|
||||
instances->info[ d->id ].command |= ExitedInstance; // upon kill, we have to set the ExitedInstance flag
|
||||
d->id = -1; // becauso our d'tor won't be called anymore
|
||||
}
|
||||
}
|
||||
|
||||
if( killOurSelf ) // kill our self takes precedence
|
||||
exit( 1 );
|
||||
else if( shutDownOurSelf )
|
||||
qApp->quit();
|
||||
else if( policyDidChange )
|
||||
emit policyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KDTOOLSCORE_UNITTESTS
|
||||
|
||||
#include <kdunittest/test.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtTest/QSignalSpy>
|
||||
|
||||
Q_DECLARE_METATYPE( KDSingleApplicationGuard::Instance );
|
||||
|
||||
static void wait( int msec )
|
||||
{
|
||||
QTime t;
|
||||
t.start();
|
||||
while( t.elapsed() < msec )
|
||||
{
|
||||
qApp->processEvents( QEventLoop::WaitForMoreEvents, msec - t.elapsed() );
|
||||
}
|
||||
}
|
||||
|
||||
static std::ostream& operator<<( std::ostream& stream, const QStringList& list )
|
||||
{
|
||||
stream << "QStringList(";
|
||||
for( QStringList::const_iterator it = list.begin(); it != list.end(); ++it )
|
||||
{
|
||||
stream << " " << it->toLocal8Bit().data();
|
||||
if( it + 1 != list.end() )
|
||||
stream << ",";
|
||||
}
|
||||
stream << " )";
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
KDAB_UNITTEST_SIMPLE( KDSingleApplicationGuard, "kdcoretools" ) {
|
||||
|
||||
// set it to an unique name
|
||||
qApp->setApplicationName( QUuid::createUuid().toString() );
|
||||
|
||||
qRegisterMetaType< KDSingleApplicationGuard::Instance >();
|
||||
|
||||
KDSingleApplicationGuard* guard3 = 0;
|
||||
QSignalSpy* spy3 = 0;
|
||||
|
||||
{
|
||||
KDSingleApplicationGuard guard1( qApp );
|
||||
assertEqual( guard1.policy(), KDSingleApplicationGuard::AutoKillOtherInstances );
|
||||
assertEqual( guard1.instances().count(), 1 );
|
||||
assertTrue( guard1.isPrimaryInstance() );
|
||||
|
||||
guard1.setPolicy( KDSingleApplicationGuard::NoPolicy );
|
||||
assertEqual( guard1.policy(), KDSingleApplicationGuard::NoPolicy );
|
||||
|
||||
QSignalSpy spy1( &guard1, SIGNAL( instanceStarted( KDSingleApplicationGuard::Instance ) ) );
|
||||
|
||||
KDSingleApplicationGuard guard2( qApp );
|
||||
assertEqual( guard1.instances().count(), 2 );
|
||||
assertEqual( guard2.instances().count(), 2 );
|
||||
assertEqual( guard2.policy(), KDSingleApplicationGuard::NoPolicy );
|
||||
assertFalse( guard2.isPrimaryInstance() );
|
||||
|
||||
wait( 1000 );
|
||||
|
||||
assertEqual( spy1.count(), 1 );
|
||||
guard3 = new KDSingleApplicationGuard( qApp );
|
||||
spy3 = new QSignalSpy( guard3, SIGNAL( becamePrimaryInstance() ) );
|
||||
assertFalse( guard3->isPrimaryInstance() );
|
||||
}
|
||||
|
||||
wait( 1000 );
|
||||
assertEqual( spy3->count(), 1 );
|
||||
assertEqual( guard3->instances().count(), 1 );
|
||||
assertTrue( guard3->isPrimaryInstance() );
|
||||
|
||||
assertEqual( guard3->instances().first().arguments, qApp->arguments() );
|
||||
|
||||
QSignalSpy spyStarted( guard3, SIGNAL( instanceStarted( KDSingleApplicationGuard::Instance ) ) );
|
||||
QSignalSpy spyExited( guard3, SIGNAL( instanceExited( KDSingleApplicationGuard::Instance ) ) );
|
||||
|
||||
{
|
||||
KDSingleApplicationGuard guard1( qApp );
|
||||
KDSingleApplicationGuard guard2( qApp );
|
||||
|
||||
wait( 1000 );
|
||||
|
||||
assertEqual( spyStarted.count(), 2 );
|
||||
}
|
||||
|
||||
wait( 1000 );
|
||||
assertEqual( spyExited.count(), 2 );
|
||||
|
||||
delete spy3;
|
||||
delete guard3;
|
||||
}
|
||||
|
||||
#endif // KDTOOLSCORE_UNITTESTS
|
||||
|
||||
#endif // QT_VERSION < 0x040400
|
@@ -0,0 +1,75 @@
|
||||
#ifndef __KDTOOLSCORE_KDSINGLEAPPLICATIONGUARD_H__
|
||||
#define __KDTOOLSCORE_KDSINGLEAPPLICATIONGUARD_H__
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include "pimpl_ptr.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
class QCoreApplication;
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
void SIGINT_handler( int sig );
|
||||
#endif
|
||||
|
||||
class DLLEXPORT KDSingleApplicationGuard : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
#ifndef Q_WS_WIN
|
||||
friend void ::SIGINT_handler( int );
|
||||
#endif
|
||||
|
||||
public:
|
||||
enum Policy
|
||||
{
|
||||
NoPolicy = 0,
|
||||
AutoKillOtherInstances = 1
|
||||
};
|
||||
|
||||
Q_PROPERTY( bool primaryInstance READ isPrimaryInstance NOTIFY becamePrimaryInstance )
|
||||
Q_PROPERTY( Policy policy READ policy WRITE setPolicy NOTIFY policyChanged )
|
||||
|
||||
explicit KDSingleApplicationGuard( QCoreApplication* parent, Policy policy = AutoKillOtherInstances );
|
||||
~KDSingleApplicationGuard();
|
||||
|
||||
bool isPrimaryInstance() const;
|
||||
|
||||
Policy policy() const;
|
||||
void setPolicy( Policy policy );
|
||||
|
||||
struct Instance
|
||||
{
|
||||
Instance( const QStringList& arguments = QStringList(), qint64 pid = -1 );
|
||||
|
||||
QStringList arguments;
|
||||
qint64 pid;
|
||||
};
|
||||
|
||||
QList< Instance > instances() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void instanceStarted( KDSingleApplicationGuard::Instance instance );
|
||||
void instanceExited( KDSingleApplicationGuard::Instance instance );
|
||||
void becamePrimaryInstance();
|
||||
void policyChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void shutdownOtherInstances();
|
||||
void killOtherInstances();
|
||||
|
||||
protected:
|
||||
void timerEvent( QTimerEvent* event );
|
||||
|
||||
private:
|
||||
class Private;
|
||||
kdtools::pimpl_ptr< Private > d;
|
||||
};
|
||||
|
||||
#if QT_VERSION < 0x040400
|
||||
#ifdef Q_CC_GNU
|
||||
#warning "Can't use KDSingleApplicationGuard with Qt versions prior to 4.4"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
32
src/libtomahawk/kdsingleapplicationguard/kdtoolsglobal.cpp
Normal file
32
src/libtomahawk/kdsingleapplicationguard/kdtoolsglobal.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "kdtoolsglobal.h"
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
struct Version {
|
||||
unsigned char v[3];
|
||||
};
|
||||
|
||||
static inline bool operator<( const Version & lhs, const Version & rhs ) {
|
||||
return std::lexicographical_compare( lhs.v, lhs.v + 3, rhs.v, rhs.v + 3 );
|
||||
}
|
||||
static inline bool operator==( const Version & lhs, const Version & rhs ) {
|
||||
return std::equal( lhs.v, lhs.v + 3, rhs.v );
|
||||
}
|
||||
KDTOOLS_MAKE_RELATION_OPERATORS( Version, static inline )
|
||||
}
|
||||
|
||||
static Version kdParseQtVersion( const char * const version ) {
|
||||
if ( !version || qstrlen( version ) < 5 || version[1] != '.' || version[3] != '.' || version[5] != 0 && version[5] != '.' && version[5] != '-' )
|
||||
return Version(); // parse error
|
||||
const Version result = { { version[0] - '0', version[2] - '0', version[4] - '0' } };
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _kdCheckQtVersion_impl( int major, int minor, int patchlevel ) {
|
||||
static const Version actual = kdParseQtVersion( qVersion() ); // do this only once each run...
|
||||
const Version requested = { { major, minor, patchlevel } };
|
||||
return actual >= requested;
|
||||
}
|
113
src/libtomahawk/kdsingleapplicationguard/kdtoolsglobal.h
Normal file
113
src/libtomahawk/kdsingleapplicationguard/kdtoolsglobal.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef __KDTOOLS_KDTOOLSGLOBAL_H__
|
||||
#define __KDTOOLS_KDTOOLSGLOBAL_H__
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#define KDAB_DISABLE_COPY( x ) private: x( const x & ); x & operator=( const x & )
|
||||
|
||||
#ifdef KDTOOLS_SHARED
|
||||
# ifdef BUILD_SHARED_KDTOOLSCORE
|
||||
# define KDTOOLSCORE_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define KDTOOLSCORE_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# ifdef BUILD_SHARED_KDTOOLSGUI
|
||||
# define KDTOOLSGUI_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define KDTOOLSGUI_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# ifdef BUILD_SHARED_KDTOOLSXML
|
||||
# define KDTOOLSXML_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define KDTOOLSXML_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# ifdef BUILD_SHARED_KDUPDATER
|
||||
# define KDTOOLS_UPDATER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define KDTOOLS_UPDATER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else // KDTOOLS_SHARED
|
||||
# define KDTOOLSCORE_EXPORT
|
||||
# define KDTOOLSGUI_EXPORT
|
||||
# define KDTOOLSXML_EXPORT
|
||||
# define KDTOOLS_UPDATER_EXPORT
|
||||
#endif // KDTOOLS_SHARED
|
||||
|
||||
#define MAKEINCLUDES_EXPORT
|
||||
|
||||
#define DOXYGEN_PROPERTY( x )
|
||||
#ifdef DOXYGEN_RUN
|
||||
# define KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( func ) operator unspecified_bool_type() const { return func; }
|
||||
# define KDAB_USING_SAFE_BOOL_OPERATOR( Class ) operator unspecified_bool_type() const;
|
||||
#else
|
||||
# define KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( func ) \
|
||||
private: struct __safe_bool_dummy__ { void nonnull() {} }; \
|
||||
typedef void ( __safe_bool_dummy__::*unspecified_bool_type )(); \
|
||||
public: \
|
||||
operator unspecified_bool_type() const { \
|
||||
return ( func ) ? &__safe_bool_dummy__::nonnull : 0 ; \
|
||||
}
|
||||
#define KDAB_USING_SAFE_BOOL_OPERATOR( Class ) \
|
||||
using Class::operator Class::unspecified_bool_type;
|
||||
#endif
|
||||
|
||||
#define KDTOOLS_MAKE_RELATION_OPERATORS( Class, linkage ) \
|
||||
linkage bool operator>( const Class & lhs, const Class & rhs ) { \
|
||||
return operator<( rhs, lhs ); \
|
||||
} \
|
||||
linkage bool operator!=( const Class & lhs, const Class & rhs ) { \
|
||||
return !operator==( lhs, rhs ); \
|
||||
} \
|
||||
linkage bool operator<=( const Class & lhs, const Class & rhs ) { \
|
||||
return !operator>( lhs, rhs ); \
|
||||
} \
|
||||
linkage bool operator>=( const Class & lhs, const Class & rhs ) { \
|
||||
return !operator<( lhs, rhs ); \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T & __kdtools__dereference_for_methodcall( T & o ) {
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T & __kdtools__dereference_for_methodcall( T * o ) {
|
||||
return *o;
|
||||
}
|
||||
|
||||
#define KDAB_SET_OBJECT_NAME( x ) __kdtools__dereference_for_methodcall( x ).setObjectName( QLatin1String( #x ) )
|
||||
|
||||
KDTOOLSCORE_EXPORT bool _kdCheckQtVersion_impl( int major, int minor=0, int patchlevel=0 );
|
||||
static inline bool kdCheckQtVersion( unsigned int major, unsigned int minor=0, unsigned int patchlevel=0 ) {
|
||||
return (major<<16|minor<<8|patchlevel) <= static_cast<unsigned int>(QT_VERSION)
|
||||
|| _kdCheckQtVersion_impl( major, minor, patchlevel );
|
||||
}
|
||||
|
||||
#define KDTOOLS_DECLARE_PRIVATE_BASE( Class ) \
|
||||
protected: \
|
||||
class Private; \
|
||||
Private * d_func() { return _d; } \
|
||||
const Private * d_func() const { return _d; } \
|
||||
Class( Private * _d_, bool b ) : _d( _d_ ) { init(b); } \
|
||||
private: \
|
||||
void init(bool); \
|
||||
private: \
|
||||
Private * _d
|
||||
|
||||
#define KDTOOLS_DECLARE_PRIVATE_DERIVED( Class, Base ) \
|
||||
protected: \
|
||||
class Private; \
|
||||
Private * d_func() { \
|
||||
return reinterpret_cast<Private*>( Base::d_func() ); \
|
||||
} \
|
||||
const Private * d_func() const { \
|
||||
return reinterpret_cast<const Private*>( Base::d_func() ); \
|
||||
} \
|
||||
Class( Private * _d_, bool b ) \
|
||||
: Base( reinterpret_cast<Base::Private*>(_d_), b ) { init(b); } \
|
||||
private: \
|
||||
void init(bool)
|
||||
|
||||
|
||||
#endif /* __KDTOOLS_KDTOOLSGLOBAL_H__ */
|
||||
|
349
src/libtomahawk/kdsingleapplicationguard/license-gpl
Normal file
349
src/libtomahawk/kdsingleapplicationguard/license-gpl
Normal file
@@ -0,0 +1,349 @@
|
||||
|
||||
The KD Tools Library is Copyright (C) 2001-2003 Klar<61>lvdalens Datakonsult AB.
|
||||
|
||||
You may use, distribute and copy the KD Tools Library under the terms of
|
||||
GNU General Public License version 2, which is displayed below.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
-------------------------------------------------------------------------
|
203
src/libtomahawk/kdsingleapplicationguard/pimpl_ptr.cpp
Normal file
203
src/libtomahawk/kdsingleapplicationguard/pimpl_ptr.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
#include "pimpl_ptr.h"
|
||||
|
||||
/*!
|
||||
\class pimpl_ptr:
|
||||
\ingroup core smartptr
|
||||
\brief Owning pointer for private implementations
|
||||
\since_c 2.1
|
||||
|
||||
(The exception safety of this class has not been evaluated yet.)
|
||||
|
||||
pimpl_ptr is a smart immutable pointer, which owns the contained object. Unlike other smart pointers,
|
||||
it creates a standard constructed object when instanciated via the
|
||||
\link pimpl_ptr() standard constructor\endlink.
|
||||
Additionally, pimpl_ptr respects constness of the pointer object and returns \c const \c T* for
|
||||
a const pimpl_ptr object.
|
||||
|
||||
The content of a pimpl_ptr cannot be changed during it's lifetime.
|
||||
|
||||
\section general-use General Use
|
||||
|
||||
The general use case of pimpl_ptr is the "Pimpl Idiom", i.e. hiding the private implementation of a class
|
||||
from the user's compiler which see \c MyClass as
|
||||
|
||||
\code
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass();
|
||||
~MyClass();
|
||||
|
||||
// public class API
|
||||
int value() const;
|
||||
|
||||
private:
|
||||
class Private; // defined later
|
||||
kdtools::pimpl_ptr< Private > d;
|
||||
};
|
||||
\endcode
|
||||
|
||||
but not the private parts of it. These can only be seen (and accessed) by the code knowing \c MyClass::Private:
|
||||
|
||||
\code
|
||||
class MyClass::Private
|
||||
{
|
||||
public:
|
||||
int value;
|
||||
};
|
||||
|
||||
MyClass::MyClass()
|
||||
{
|
||||
// d was automatically filled with new Private
|
||||
d->value = 42;
|
||||
}
|
||||
|
||||
MyClass::~MyClass()
|
||||
{
|
||||
// the content of d gets deleted automatically
|
||||
}
|
||||
|
||||
int MyClass::value() const
|
||||
{
|
||||
// access the private part:
|
||||
// since MyClass::value() is const, the returned pointee is const, too
|
||||
return d->value;
|
||||
}
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn pimpl_ptr::pimpl_ptr()
|
||||
|
||||
Default constructor. Constructs a pimpl_tr that contains (owns) a standard constructed
|
||||
instance of \c T.
|
||||
|
||||
\post \c *this owns a new object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn pimpl_ptr::pimpl_ptr( T * t )
|
||||
|
||||
Constructor. Constructs a pimpl_ptr that contains (owns) \a t.
|
||||
|
||||
\post get() == obj
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn pimpl_ptr::~pimpl_ptr()
|
||||
|
||||
Destructor.
|
||||
|
||||
\post The object previously owned by \c *this has been deleted.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T * pimpl_ptr::get() const
|
||||
|
||||
\returns a const pointer to the contained (owned) object.
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T * pimpl_ptr::get()
|
||||
|
||||
\returns a pointer to the contained (owned) object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T & pimpl_ptr::operator*() const
|
||||
|
||||
Dereference operator. Returns \link get() *get()\endlink.
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T & pimpl_ptr::operator*()
|
||||
|
||||
Dereference operator. Returns \link get() *get()\endlink.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn const T * pimpl_ptr::operator->() const
|
||||
|
||||
Member-by-pointer operator. Returns get().
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn T * pimpl_ptr::operator->()
|
||||
|
||||
Member-by-pointer operator. Returns get().
|
||||
*/
|
||||
|
||||
#ifdef KDTOOLSCORE_UNITTESTS
|
||||
|
||||
#include <kdunittest/test.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ConstTester
|
||||
{
|
||||
bool isConst()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isConst() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
KDAB_UNITTEST_SIMPLE( pimpl_ptr, "kdcoretools" ) {
|
||||
|
||||
{
|
||||
kdtools::pimpl_ptr< QObject > p;
|
||||
assertNotNull( p.get() );
|
||||
assertNull( p->parent() );
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
QPointer< QObject > o;
|
||||
{
|
||||
kdtools::pimpl_ptr< QObject > qobject( new QObject );
|
||||
o = qobject.get();
|
||||
assertEqual( o, qobject.operator->() );
|
||||
assertEqual( o, &(qobject.operator*()) );
|
||||
}
|
||||
assertNull( o );
|
||||
}
|
||||
|
||||
{
|
||||
const kdtools::pimpl_ptr< QObject > qobject( new QObject );
|
||||
const QObject* o = qobject.get();
|
||||
assertEqual( o, qobject.operator->() );
|
||||
assertEqual( o, &(qobject.operator*()) );
|
||||
}
|
||||
|
||||
{
|
||||
kdtools::pimpl_ptr< QObject > o1;
|
||||
assertTrue( o1 );
|
||||
kdtools::pimpl_ptr< QObject > o2( 0 );
|
||||
assertFalse( o2 );
|
||||
}
|
||||
|
||||
{
|
||||
const kdtools::pimpl_ptr< ConstTester > o1;
|
||||
kdtools::pimpl_ptr< ConstTester > o2;
|
||||
assertTrue( o1->isConst() );
|
||||
assertFalse( o2->isConst() );
|
||||
assertTrue( (*o1).isConst() );
|
||||
assertFalse( (*o2).isConst() );
|
||||
assertTrue( o1.get()->isConst() );
|
||||
assertFalse( o2.get()->isConst() );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // KDTOOLSCORE_UNITTESTS
|
44
src/libtomahawk/kdsingleapplicationguard/pimpl_ptr.h
Normal file
44
src/libtomahawk/kdsingleapplicationguard/pimpl_ptr.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef __KDTOOLSCORE__PIMPL_PTR_H__
|
||||
#define __KDTOOLSCORE__PIMPL_PTR_H__
|
||||
|
||||
#include "kdtoolsglobal.h"
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
namespace kdtools {
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class pimpl_ptr {
|
||||
KDAB_DISABLE_COPY( pimpl_ptr );
|
||||
T * d;
|
||||
public:
|
||||
pimpl_ptr() : d( new T ) {}
|
||||
explicit pimpl_ptr( T * t ) : d( t ) {}
|
||||
~pimpl_ptr() { delete d; d = 0; }
|
||||
|
||||
T * get() { return d; }
|
||||
const T * get() const { return d; }
|
||||
|
||||
T * operator->() { return get(); }
|
||||
const T * operator->() const { return get(); }
|
||||
|
||||
T & operator*() { return *get(); }
|
||||
const T & operator*() const { return *get(); }
|
||||
|
||||
KDAB_IMPLEMENT_SAFE_BOOL_OPERATOR( get() )
|
||||
};
|
||||
|
||||
// these are not implemented, so's we can catch their use at
|
||||
// link-time. Leaving them undeclared would open up a comparison
|
||||
// via operator unspecified-bool-type().
|
||||
template <typename T, typename S>
|
||||
void operator==( const pimpl_ptr<T> &, const pimpl_ptr<S> & );
|
||||
template <typename T, typename S>
|
||||
void operator!=( const pimpl_ptr<T> &, const pimpl_ptr<S> & );
|
||||
|
||||
#ifndef DOXYGEN_RUN
|
||||
} // namespace kdtools
|
||||
#endif
|
||||
|
||||
#endif /* __KDTOOLSCORE__PIMPL_PTR_H__ */
|
||||
|
@@ -62,16 +62,12 @@ Connection::Connection( Servent* parent )
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
qDebug() << "DTOR connection (super)" << id() << thread();
|
||||
qDebug() << "DTOR connection (super)" << id() << thread() << m_sock.isNull();
|
||||
if( !m_sock.isNull() )
|
||||
{
|
||||
qDebug() << "deleteLatering sock" << m_sock;
|
||||
// qDebug() << "deleteLatering sock" << m_sock;
|
||||
m_sock->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "no valid sock to delete";
|
||||
}
|
||||
|
||||
delete m_statstimer;
|
||||
}
|
||||
@@ -118,7 +114,7 @@ Connection::setFirstMessage( msg_ptr m )
|
||||
void
|
||||
Connection::shutdown( bool waitUntilSentAll )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << waitUntilSentAll;
|
||||
qDebug() << Q_FUNC_INFO << waitUntilSentAll << id();
|
||||
if ( m_do_shutdown )
|
||||
{
|
||||
//qDebug() << id() << " already shutting down";
|
||||
@@ -128,7 +124,7 @@ Connection::shutdown( bool waitUntilSentAll )
|
||||
m_do_shutdown = true;
|
||||
if ( !waitUntilSentAll )
|
||||
{
|
||||
qDebug() << "Shutting down immediately " << id();
|
||||
// qDebug() << "Shutting down immediately " << id();
|
||||
actualShutdown();
|
||||
}
|
||||
else
|
||||
@@ -146,10 +142,9 @@ Connection::shutdown( bool waitUntilSentAll )
|
||||
void
|
||||
Connection::actualShutdown()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << Q_FUNC_INFO << m_actually_shutting_down << id();
|
||||
if( m_actually_shutting_down )
|
||||
{
|
||||
qDebug() << "(already actually shutting down)";
|
||||
return;
|
||||
}
|
||||
m_actually_shutting_down = true;
|
||||
@@ -159,7 +154,7 @@ Connection::actualShutdown()
|
||||
m_sock->disconnectFromHost();
|
||||
}
|
||||
|
||||
qDebug() << "EMITTING finished()";
|
||||
// qDebug() << "EMITTING finished()";
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
@@ -75,6 +75,13 @@ ControlConnection::setup()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << id() << name();
|
||||
|
||||
if ( !m_source.isNull() )
|
||||
{
|
||||
qDebug() << "This source seems to be online already.";
|
||||
Q_ASSERT( false );
|
||||
return;
|
||||
}
|
||||
|
||||
QString friendlyName;
|
||||
if ( Servent::isIPWhitelisted( m_sock->peerAddress() ) )
|
||||
{
|
||||
|
@@ -75,7 +75,7 @@ DBSyncConnection::~DBSyncConnection()
|
||||
void
|
||||
DBSyncConnection::idleTimeout()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "*************";
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
shutdown( true );
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ DBSyncConnection::changeState( State newstate )
|
||||
m_state = newstate;
|
||||
qDebug() << "DBSYNC State changed from" << s << "to" << newstate;
|
||||
emit stateChanged( newstate, s, "" );
|
||||
|
||||
if ( newstate == SYNCED )
|
||||
{
|
||||
qDebug() << "Synced :)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +192,7 @@ DBSyncConnection::handleMsg( msg_ptr msg )
|
||||
msg->is( Msg::DBOP ) &&
|
||||
msg->payload() == "ok" )
|
||||
{
|
||||
qDebug() << "No ops to apply, we are synced.";
|
||||
// qDebug() << "No ops to apply, we are synced.";
|
||||
changeState( SYNCED );
|
||||
// calc the collection stats, to updates the "X tracks" in the sidebar etc
|
||||
// this is done automatically if you run a dbcmd to add files.
|
||||
|
@@ -676,12 +676,12 @@ Servent::checkACL( const Connection* conn, const QString &nodeid, bool showDialo
|
||||
qDebug() << "ACL for this node not found";
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon( QMessageBox::Question );
|
||||
msgBox.setText( "Incoming Connection Attempt" );
|
||||
msgBox.setInformativeText( QString( "Another Tomahawk instance is attempting to connect to you. Select whether to allow or deny this connection.\n\nPeer name: %1\nPeer ID: %2\n\nRemember: Only allow peers to connect if you have the legal right for them to stream music from you.").arg( conn->name(), nodeid ) );
|
||||
QPushButton *denyButton = msgBox.addButton( "Deny", QMessageBox::HelpRole );
|
||||
QPushButton *alwaysDenyButton = msgBox.addButton( "Always Deny", QMessageBox::YesRole );
|
||||
QPushButton *allowButton = msgBox.addButton( "Allow", QMessageBox::NoRole );
|
||||
QPushButton *alwaysAllowButton = msgBox.addButton( "Always Allow", QMessageBox::ActionRole );
|
||||
msgBox.setText( tr( "Incoming Connection Attempt" ) );
|
||||
msgBox.setInformativeText( tr( "Another Tomahawk instance is attempting to connect to you. Select whether to allow or deny this connection.\n\nPeer name: %1\nPeer ID: %2\n\nRemember: Only allow peers to connect if you have the legal right for them to stream music from you.").arg( conn->name(), nodeid ) );
|
||||
QPushButton *denyButton = msgBox.addButton( tr( "Deny" ), QMessageBox::HelpRole );
|
||||
QPushButton *alwaysDenyButton = msgBox.addButton( tr( "Always Deny" ), QMessageBox::YesRole );
|
||||
QPushButton *allowButton = msgBox.addButton( tr( "Allow" ), QMessageBox::NoRole );
|
||||
QPushButton *alwaysAllowButton = msgBox.addButton( tr( "Always Allow" ), QMessageBox::ActionRole );
|
||||
|
||||
msgBox.setDefaultButton( denyButton );
|
||||
msgBox.setEscapeButton( denyButton );
|
||||
@@ -792,8 +792,11 @@ Servent::isIPWhitelisted( QHostAddress ip )
|
||||
bool
|
||||
Servent::connectedToSession( const QString& session )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << "Checking against " << session;
|
||||
foreach( ControlConnection* cc, m_controlconnections )
|
||||
{
|
||||
qDebug() << "Checking session " << cc->id();
|
||||
if( cc->id() == session )
|
||||
return true;
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@ Pipeline::resolve( const QList<query_ptr>& qlist, bool prioritized )
|
||||
int i = 0;
|
||||
foreach( const query_ptr& q, qlist )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << (qlonglong)q.data() << q->toString();
|
||||
// qDebug() << Q_FUNC_INFO << (qlonglong)q.data() << q->toString();
|
||||
if ( !m_qids.contains( q->id() ) )
|
||||
{
|
||||
m_qids.insert( q->id(), q );
|
||||
@@ -189,7 +189,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
if ( decQIDState( q ) == 0 )
|
||||
{
|
||||
// All resolvers have reported back their results for this query now
|
||||
qDebug() << "Finished resolving:" << q->toString();
|
||||
qDebug() << "Finished resolving:" << q->toString() << q->numResults();
|
||||
|
||||
if ( !q->solved() )
|
||||
q->onResolvingFinished();
|
||||
@@ -216,7 +216,7 @@ Pipeline::shuntNext()
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << m_qidsState.count();
|
||||
// qDebug() << Q_FUNC_INFO << m_qidsState.count();
|
||||
// Check if we are ready to dispatch more queries
|
||||
if ( m_qidsState.count() >= CONCURRENT_QUERIES )
|
||||
return;
|
||||
@@ -246,8 +246,8 @@ Pipeline::shunt( const query_ptr& q )
|
||||
|
||||
if ( q->solved() )
|
||||
{
|
||||
qDebug() << "Query solved, pipeline aborted:" << q->toString()
|
||||
<< "numresults:" << q->results().length();
|
||||
// qDebug() << "Query solved, pipeline aborted:" << q->toString()
|
||||
// << "numresults:" << q->results().length();
|
||||
|
||||
QList< result_ptr > rl;
|
||||
reportResults( q->id(), rl );
|
||||
@@ -275,7 +275,7 @@ Pipeline::shunt( const query_ptr& q )
|
||||
lasttimeout = r->timeout();
|
||||
|
||||
// resolvers aren't allowed to block in this call:
|
||||
qDebug() << "Dispatching to resolver" << r->name();
|
||||
qDebug() << "Dispatching to resolver" << r->name() << q->toString();
|
||||
|
||||
thisResolver = i;
|
||||
r->resolve( q );
|
||||
@@ -291,7 +291,7 @@ Pipeline::shunt( const query_ptr& q )
|
||||
if ( thisResolver < m_resolvers.count() )
|
||||
{
|
||||
incQIDState( q );
|
||||
qDebug() << "Shunting in" << lasttimeout << "ms, q:" << q->toString();
|
||||
// qDebug() << "Shunting in" << lasttimeout << "ms, q:" << q->toString();
|
||||
new FuncTimeout( lasttimeout, boost::bind( &Pipeline::shunt, this, q ) );
|
||||
}
|
||||
}
|
||||
@@ -329,7 +329,7 @@ Pipeline::incQIDState( const Tomahawk::query_ptr& query )
|
||||
state = m_qidsState.value( query->id() ) + 1;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "inserting to qidsstate:" << query->id() << state;
|
||||
// qDebug() << Q_FUNC_INFO << "inserting to qidsstate:" << query->id() << state;
|
||||
m_qidsState.insert( query->id(), state );
|
||||
|
||||
return state;
|
||||
@@ -344,12 +344,12 @@ Pipeline::decQIDState( const Tomahawk::query_ptr& query )
|
||||
int state = m_qidsState.value( query->id() ) - 1;
|
||||
if ( state )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "replacing" << query->id() << state;
|
||||
// qDebug() << Q_FUNC_INFO << "replacing" << query->id() << state;
|
||||
m_qidsState.insert( query->id(), state );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "removing" << query->id() << state;
|
||||
// qDebug() << Q_FUNC_INFO << "removing" << query->id() << state;
|
||||
m_qidsState.remove( query->id() );
|
||||
}
|
||||
|
||||
|
@@ -112,7 +112,7 @@ Playlist::Playlist( const source_ptr& src,
|
||||
, m_lastmodified( lastmod )
|
||||
, m_shared( shared )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "1";
|
||||
// qDebug() << Q_FUNC_INFO << "1";
|
||||
init();
|
||||
}
|
||||
|
||||
|
@@ -253,8 +253,8 @@ DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
|
||||
Q_ASSERT( !author().isNull() );
|
||||
Q_ASSERT( !author()->collection().isNull() );
|
||||
// will emit Collection::playlistCreated(...)
|
||||
qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull();
|
||||
qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName();
|
||||
// qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull();
|
||||
// qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName();
|
||||
author()->collection()->addDynamicPlaylist( self );
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ QList< dyncontrol_ptr > DynamicPlaylist::variantsToControl( const QList< QVarian
|
||||
QList<dyncontrol_ptr> realControls;
|
||||
foreach( QVariantMap controlV, controlsV ) {
|
||||
dyncontrol_ptr control = GeneratorFactory::createControl( controlV.value( "type" ).toString(), controlV.value( "selectedType" ).toString() );
|
||||
qDebug() << "CReating control with data:" << controlV;
|
||||
qDebug() << "Creating control with data:" << controlV;
|
||||
QJson::QObjectHelper::qvariant2qobject( controlV, control.data() );
|
||||
realControls << control;
|
||||
}
|
||||
|
@@ -345,6 +345,8 @@ DynamicWidget::controlsChanged()
|
||||
return;
|
||||
m_playlist->createNewRevision();
|
||||
m_seqRevLaunched++;
|
||||
|
||||
emit descriptionChanged( m_playlist->generator()->sentenceSummary() );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -356,6 +358,8 @@ DynamicWidget::controlChanged( const Tomahawk::dyncontrol_ptr& control )
|
||||
m_seqRevLaunched++;
|
||||
|
||||
showPreview();
|
||||
|
||||
emit descriptionChanged( m_playlist->generator()->sentenceSummary() );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -94,6 +94,9 @@ public slots:
|
||||
void playlistChanged( PlaylistInterface* );
|
||||
void tracksAdded();
|
||||
|
||||
signals:
|
||||
void descriptionChanged( const QString& caption );
|
||||
|
||||
private slots:
|
||||
void generate( int = -1 );
|
||||
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
|
||||
|
@@ -72,14 +72,21 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
|
||||
if ( !item || item->query().isNull() )
|
||||
return;
|
||||
|
||||
float opacity = 0.0;
|
||||
painter->save();
|
||||
if ( item->query()->results().count() )
|
||||
painter->setOpacity( item->query()->results().at( 0 )->score() );
|
||||
else
|
||||
painter->setOpacity( 0.0 );
|
||||
opacity = item->query()->results().first()->score();
|
||||
|
||||
if ( painter->opacity() < 0.3 )
|
||||
painter->setOpacity( 0.3 );
|
||||
QColor textcol, bgcol;
|
||||
textcol = option.palette.color( QPalette::Foreground );
|
||||
bgcol = option.palette.color( QPalette::Background );
|
||||
|
||||
opacity = qMax( (float)0.3, opacity );
|
||||
int r = textcol.red(), g = textcol.green(), b = textcol.blue();
|
||||
r = opacity * r + ( 1 - opacity ) * bgcol.red();
|
||||
g = opacity * g + ( 1 - opacity ) * bgcol.green();
|
||||
b = opacity * b + ( 1 - opacity ) * bgcol.blue();
|
||||
textcol = QColor( r, g, b );
|
||||
|
||||
if ( item->isPlaying() )
|
||||
{
|
||||
@@ -113,6 +120,13 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( const QStyleOptionViewItem *vioption = qstyleoption_cast<const QStyleOptionViewItem *>(&option))
|
||||
{
|
||||
QStyleOptionViewItemV4 o( *vioption );
|
||||
o.palette.setColor( QPalette::Text, textcol );
|
||||
QStyledItemDelegate::paint( painter, o, index );
|
||||
}
|
||||
else
|
||||
QStyledItemDelegate::paint( painter, option, index );
|
||||
}
|
||||
|
||||
|
@@ -553,6 +553,13 @@ PlaylistManager::setPage( ViewPage* page, bool trackHistory )
|
||||
if ( !AudioEngine::instance()->isPlaying() )
|
||||
AudioEngine::instance()->setPlaylist( currentPlaylistInterface() );
|
||||
|
||||
// UGH!
|
||||
if( QObject* obj = dynamic_cast< QObject* >( currentPage() ) ) {
|
||||
// qDebug() << SIGNAL( descriptionChanged( QString ) ) << QMetaObject::normalizedSignature( SIGNAL( descriptionChanged( QString ) ) ) << obj->metaObject()->indexOfSignal( QMetaObject::normalizedSignature( SIGNAL( descriptionChanged( QString ) ) ) );
|
||||
// if( obj->metaObject()->indexOfSignal( QMetaObject::normalizedSignature( SIGNAL( descriptionChanged( QString ) ) ) ) > -1 ) // if the signal exists (just to hide the qobject runtime warning...)
|
||||
connect( obj, SIGNAL( descriptionChanged( QString ) ), m_infobar, SLOT( setDescription( QString ) ) );
|
||||
}
|
||||
|
||||
m_stack->setCurrentWidget( page->widget() );
|
||||
updateView();
|
||||
}
|
||||
|
@@ -396,12 +396,16 @@ PlaylistModel::playlistEntries() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( unsigned int row, bool moreToCome )
|
||||
{
|
||||
removeIndex( index( row, 0, QModelIndex() ), moreToCome );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
if ( isReadOnly() )
|
||||
return;
|
||||
|
||||
TrackModel::removeIndex( index );
|
||||
|
||||
if ( !moreToCome && !m_playlist.isNull() )
|
||||
|
@@ -62,6 +62,7 @@ public:
|
||||
|
||||
void insert( unsigned int row, const Tomahawk::query_ptr& query );
|
||||
|
||||
void remove( unsigned int row, bool moreToCome = false );
|
||||
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
|
||||
|
||||
signals:
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
#include "album.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -302,7 +303,7 @@ TrackModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
|
||||
// qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
|
||||
QMetaObject::invokeMethod( this, "removeIndex",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(const QModelIndex, index),
|
||||
@@ -311,8 +312,6 @@ TrackModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( index.column() > 0 )
|
||||
return;
|
||||
|
||||
@@ -370,3 +369,16 @@ TrackModel::onPlaybackStopped()
|
||||
oldEntry->setIsPlaying( false );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::ensureResolved()
|
||||
{
|
||||
for( int i = 0; i < rowCount( QModelIndex() ); i++ )
|
||||
{
|
||||
query_ptr query = itemFromIndex( index( i, 0, QModelIndex() ) )->query();
|
||||
|
||||
if ( !query->numResults() )
|
||||
Pipeline::instance()->resolve( query );
|
||||
}
|
||||
}
|
||||
|
@@ -76,6 +76,8 @@ public:
|
||||
virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; }
|
||||
virtual bool shuffled() const { return false; }
|
||||
|
||||
virtual void ensureResolved();
|
||||
|
||||
virtual void append( const Tomahawk::query_ptr& query ) = 0;
|
||||
|
||||
PlItem* itemFromIndex( const QModelIndex& index ) const;
|
||||
|
@@ -1,199 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qtlocalpeer.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QTime>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <QtCore/QLibrary>
|
||||
#include <QtCore/qt_windows.h>
|
||||
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||
#endif
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
namespace QtLP_Private {
|
||||
#include "qtlockedfile.cpp"
|
||||
#if defined(Q_OS_WIN)
|
||||
#include "qtlockedfile_win.cpp"
|
||||
#else
|
||||
#include "qtlockedfile_unix.cpp"
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* QtLocalPeer::ack = "ack";
|
||||
|
||||
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
|
||||
: QObject(parent), id(appId)
|
||||
{
|
||||
QString prefix = id;
|
||||
if (id.isEmpty()) {
|
||||
id = QCoreApplication::applicationFilePath();
|
||||
#if defined(Q_OS_WIN)
|
||||
id = id.toLower();
|
||||
#endif
|
||||
prefix = id.section(QLatin1Char('/'), -1);
|
||||
}
|
||||
prefix.remove(QRegExp("[^a-zA-Z]"));
|
||||
prefix.truncate(6);
|
||||
|
||||
QByteArray idc = id.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
socketName = QLatin1String("qtsingleapp-") + prefix
|
||||
+ QLatin1Char('-') + QString::number(idNum, 16);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
if (!pProcessIdToSessionId) {
|
||||
QLibrary lib("kernel32");
|
||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||
}
|
||||
if (pProcessIdToSessionId) {
|
||||
DWORD sessionId = 0;
|
||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||
}
|
||||
#else
|
||||
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||
#endif
|
||||
|
||||
server = new QLocalServer(this);
|
||||
QString lockName = QDir(QDir::tempPath()).absolutePath()
|
||||
+ QLatin1Char('/') + socketName
|
||||
+ QLatin1String("-lockfile");
|
||||
lockFile.setFileName(lockName);
|
||||
lockFile.open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool QtLocalPeer::isClient()
|
||||
{
|
||||
if (lockFile.isLocked())
|
||||
return false;
|
||||
|
||||
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
|
||||
return true;
|
||||
|
||||
bool res = server->listen(socketName);
|
||||
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
|
||||
// ### Workaround
|
||||
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
||||
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||
res = server->listen(socketName);
|
||||
}
|
||||
#endif
|
||||
if (!res)
|
||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||
{
|
||||
if (!isClient())
|
||||
return false;
|
||||
|
||||
QLocalSocket socket;
|
||||
bool connOk = false;
|
||||
for(int i = 0; i < 2; i++) {
|
||||
// Try twice, in case the other instance is just starting up
|
||||
socket.connectToServer(socketName);
|
||||
connOk = socket.waitForConnected(timeout/2);
|
||||
if (connOk || i)
|
||||
break;
|
||||
int ms = 250;
|
||||
#if defined(Q_OS_WIN)
|
||||
Sleep(DWORD(ms));
|
||||
#else
|
||||
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
if (!connOk)
|
||||
return false;
|
||||
|
||||
QByteArray uMsg(message.toUtf8());
|
||||
QDataStream ds(&socket);
|
||||
ds.writeBytes(uMsg.constData(), uMsg.size());
|
||||
bool res = socket.waitForBytesWritten(timeout);
|
||||
if (res) {
|
||||
res &= socket.waitForReadyRead(timeout); // wait for ack
|
||||
if (res)
|
||||
res &= (socket.read(qstrlen(ack)) == ack);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void QtLocalPeer::receiveConnection()
|
||||
{
|
||||
QLocalSocket* socket = server->nextPendingConnection();
|
||||
if (!socket)
|
||||
return;
|
||||
|
||||
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
||||
socket->waitForReadyRead();
|
||||
QDataStream ds(socket);
|
||||
QByteArray uMsg;
|
||||
quint32 remaining;
|
||||
ds >> remaining;
|
||||
uMsg.resize(remaining);
|
||||
int got = 0;
|
||||
char* uMsgBuf = uMsg.data();
|
||||
do {
|
||||
got = ds.readRawData(uMsgBuf, remaining);
|
||||
remaining -= got;
|
||||
uMsgBuf += got;
|
||||
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
||||
if (got < 0) {
|
||||
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
QString message(QString::fromUtf8(uMsg));
|
||||
socket->write(ack, qstrlen(ack));
|
||||
socket->waitForBytesWritten(1000);
|
||||
delete socket;
|
||||
emit messageReceived(message); //### (might take a long time to return)
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QtNetwork/QLocalServer>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
class QtLocalPeer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout);
|
||||
QString applicationId() const
|
||||
{ return id; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void receiveConnection();
|
||||
|
||||
protected:
|
||||
QString id;
|
||||
QString socketName;
|
||||
QLocalServer* server;
|
||||
QtLP_Private::QtLockedFile lockFile;
|
||||
|
||||
private:
|
||||
static const char* ack;
|
||||
};
|
@@ -1,192 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
/*!
|
||||
\class QtLockedFile
|
||||
|
||||
\brief The QtLockedFile class extends QFile with advisory locking
|
||||
functions.
|
||||
|
||||
A file may be locked in read or write mode. Multiple instances of
|
||||
\e QtLockedFile, created in multiple processes running on the same
|
||||
machine, may have a file locked in read mode. Exactly one instance
|
||||
may have it locked in write mode. A read and a write lock cannot
|
||||
exist simultaneously on the same file.
|
||||
|
||||
The file locks are advisory. This means that nothing prevents
|
||||
another process from manipulating a locked file using QFile or
|
||||
file system functions offered by the OS. Serialization is only
|
||||
guaranteed if all processes that access the file use
|
||||
QLockedFile. Also, while holding a lock on a file, a process
|
||||
must not open the same file again (through any API), or locks
|
||||
can be unexpectedly lost.
|
||||
|
||||
The lock provided by an instance of \e QtLockedFile is released
|
||||
whenever the program terminates. This is true even when the
|
||||
program crashes and no destructors are called.
|
||||
*/
|
||||
|
||||
/*! \enum QtLockedFile::LockMode
|
||||
|
||||
This enum describes the available lock modes.
|
||||
|
||||
\value ReadLock A read lock.
|
||||
\value WriteLock A write lock.
|
||||
\value NoLock Neither a read lock nor a write lock.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an unlocked \e QtLockedFile object. This constructor
|
||||
behaves in the same way as \e QFile::QFile().
|
||||
|
||||
\sa QFile::QFile()
|
||||
*/
|
||||
QtLockedFile::QtLockedFile()
|
||||
: QFile()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
#endif
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||
constructor behaves in the same way as \e QFile::QFile(const
|
||||
QString&).
|
||||
|
||||
\sa QFile::QFile()
|
||||
*/
|
||||
QtLockedFile::QtLockedFile(const QString &name)
|
||||
: QFile(name)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
#endif
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
Opens the file in OpenMode \a mode.
|
||||
|
||||
This is identical to QFile::open(), with the one exception that the
|
||||
Truncate mode flag is disallowed. Truncation would conflict with the
|
||||
advisory file locking, since the file would be modified before the
|
||||
write lock is obtained. If truncation is required, use resize(0)
|
||||
after obtaining the write lock.
|
||||
|
||||
Returns true if successful; otherwise false.
|
||||
|
||||
\sa QFile::open(), QFile::resize()
|
||||
*/
|
||||
bool QtLockedFile::open(OpenMode mode)
|
||||
{
|
||||
if (mode & QIODevice::Truncate) {
|
||||
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||
return false;
|
||||
}
|
||||
return QFile::open(mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \e true if this object has a in read or write lock;
|
||||
otherwise returns \e false.
|
||||
|
||||
\sa lockMode()
|
||||
*/
|
||||
bool QtLockedFile::isLocked() const
|
||||
{
|
||||
return m_lock_mode != NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the type of lock currently held by this object, or \e
|
||||
QtLockedFile::NoLock.
|
||||
|
||||
\sa isLocked()
|
||||
*/
|
||||
QtLockedFile::LockMode QtLockedFile::lockMode() const
|
||||
{
|
||||
return m_lock_mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
||||
|
||||
Obtains a lock of type \a mode. The file must be opened before it
|
||||
can be locked.
|
||||
|
||||
If \a block is true, this function will block until the lock is
|
||||
aquired. If \a block is false, this function returns \e false
|
||||
immediately if the lock cannot be aquired.
|
||||
|
||||
If this object already has a lock of type \a mode, this function
|
||||
returns \e true immediately. If this object has a lock of a
|
||||
different type than \a mode, the lock is first released and then a
|
||||
new lock is obtained.
|
||||
|
||||
This function returns \e true if, after it executes, the file is
|
||||
locked by this object, and \e false otherwise.
|
||||
|
||||
\sa unlock(), isLocked(), lockMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QtLockedFile::unlock()
|
||||
|
||||
Releases a lock.
|
||||
|
||||
If the object has no lock, this function returns immediately.
|
||||
|
||||
This function returns \e true if, after it executes, the file is
|
||||
not locked by this object, and \e false otherwise.
|
||||
|
||||
\sa lock(), isLocked(), lockMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QtLockedFile::~QtLockedFile()
|
||||
|
||||
Destroys the \e QtLockedFile object. If any locks were held, they
|
||||
are released.
|
||||
*/
|
@@ -1,96 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLOCKEDFILE_H
|
||||
#define QTLOCKEDFILE_H
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtCore/QVector>
|
||||
#endif
|
||||
|
||||
#if defined(Q_WS_WIN)
|
||||
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
|
||||
# define QT_QTLOCKEDFILE_EXPORT
|
||||
# elif defined(QT_QTLOCKEDFILE_IMPORT)
|
||||
# if defined(QT_QTLOCKEDFILE_EXPORT)
|
||||
# undef QT_QTLOCKEDFILE_EXPORT
|
||||
# endif
|
||||
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
|
||||
# elif defined(QT_QTLOCKEDFILE_EXPORT)
|
||||
# undef QT_QTLOCKEDFILE_EXPORT
|
||||
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
|
||||
# endif
|
||||
#else
|
||||
# define QT_QTLOCKEDFILE_EXPORT
|
||||
#endif
|
||||
|
||||
namespace QtLP_Private {
|
||||
|
||||
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
|
||||
{
|
||||
public:
|
||||
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
||||
|
||||
QtLockedFile();
|
||||
QtLockedFile(const QString &name);
|
||||
~QtLockedFile();
|
||||
|
||||
bool open(OpenMode mode);
|
||||
|
||||
bool lock(LockMode mode, bool block = true);
|
||||
bool unlock();
|
||||
bool isLocked() const;
|
||||
LockMode lockMode() const;
|
||||
|
||||
private:
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE wmutex;
|
||||
Qt::HANDLE rmutex;
|
||||
QVector<Qt::HANDLE> rmutexes;
|
||||
QString mutexname;
|
||||
|
||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||
|
||||
#endif
|
||||
LockMode m_lock_mode;
|
||||
};
|
||||
}
|
||||
#endif
|
@@ -1,114 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
||||
int cmd = block ? F_SETLKW : F_SETLK;
|
||||
int ret = fcntl(handle(), cmd, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QtLockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isLocked())
|
||||
return true;
|
||||
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = F_UNLCK;
|
||||
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock_mode = NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
QtLockedFile::~QtLockedFile()
|
||||
{
|
||||
if (isOpen())
|
||||
unlock();
|
||||
}
|
||||
|
@@ -1,208 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
#include <qt_windows.h>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#define MUTEX_PREFIX "QtLockedFile mutex "
|
||||
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
||||
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
|
||||
|
||||
#define TCHAR WCHAR
|
||||
|
||||
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
||||
{
|
||||
if (mutexname.isEmpty()) {
|
||||
QFileInfo fi(*this);
|
||||
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||
+ fi.absoluteFilePath().toLower();
|
||||
}
|
||||
QString mname(mutexname);
|
||||
if (idx >= 0)
|
||||
mname += QString::number(idx);
|
||||
|
||||
Qt::HANDLE mutex;
|
||||
if (doCreate) {
|
||||
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
|
||||
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
|
||||
if (!mutex) {
|
||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
|
||||
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
|
||||
if (!mutex) {
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return mutex;
|
||||
}
|
||||
|
||||
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
||||
{
|
||||
Q_ASSERT(mutex);
|
||||
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||
switch (res) {
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
return true;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
|
||||
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||
return false;
|
||||
|
||||
if (!waitMutex(wmutex, block))
|
||||
return false;
|
||||
|
||||
if (mode == ReadLock) {
|
||||
int idx = 0;
|
||||
for (; idx < MAX_READERS; idx++) {
|
||||
rmutex = getMutexHandle(idx, false);
|
||||
if (!rmutex || waitMutex(rmutex, false))
|
||||
break;
|
||||
CloseHandle(rmutex);
|
||||
}
|
||||
bool ok = true;
|
||||
if (idx >= MAX_READERS) {
|
||||
qWarning("QtLockedFile::lock(): too many readers");
|
||||
rmutex = 0;
|
||||
ok = false;
|
||||
}
|
||||
else if (!rmutex) {
|
||||
rmutex = getMutexHandle(idx, true);
|
||||
if (!rmutex || !waitMutex(rmutex, false))
|
||||
ok = false;
|
||||
}
|
||||
if (!ok && rmutex) {
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
ReleaseMutex(wmutex);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(rmutexes.isEmpty());
|
||||
for (int i = 0; i < MAX_READERS; i++) {
|
||||
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||
if (mutex)
|
||||
rmutexes.append(mutex);
|
||||
}
|
||||
if (rmutexes.size()) {
|
||||
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||
TRUE, block ? INFINITE : 0);
|
||||
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||
if (res != WAIT_TIMEOUT)
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtLockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isLocked())
|
||||
return true;
|
||||
|
||||
if (m_lock_mode == ReadLock) {
|
||||
ReleaseMutex(rmutex);
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
else {
|
||||
foreach(Qt::HANDLE mutex, rmutexes) {
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
}
|
||||
rmutexes.clear();
|
||||
ReleaseMutex(wmutex);
|
||||
}
|
||||
|
||||
m_lock_mode = QtLockedFile::NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
QtLockedFile::~QtLockedFile()
|
||||
{
|
||||
if (isOpen())
|
||||
unlock();
|
||||
if (wmutex)
|
||||
CloseHandle(wmutex);
|
||||
}
|
@@ -1,344 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qtsingleapplication.h"
|
||||
#include "qtlocalpeer.h"
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
|
||||
/*!
|
||||
\class QtSingleApplication qtsingleapplication.h
|
||||
\brief The QtSingleApplication class provides an API to detect and
|
||||
communicate with running instances of an application.
|
||||
|
||||
This class allows you to create applications where only one
|
||||
instance should be running at a time. I.e., if the user tries to
|
||||
launch another instance, the already running instance will be
|
||||
activated instead. Another usecase is a client-server system,
|
||||
where the first started instance will assume the role of server,
|
||||
and the later instances will act as clients of that server.
|
||||
|
||||
By default, the full path of the executable file is used to
|
||||
determine whether two processes are instances of the same
|
||||
application. You can also provide an explicit identifier string
|
||||
that will be compared instead.
|
||||
|
||||
The application should create the QtSingleApplication object early
|
||||
in the startup phase, and call isRunning() to find out if another
|
||||
instance of this application is already running. If isRunning()
|
||||
returns false, it means that no other instance is running, and
|
||||
this instance has assumed the role as the running instance. In
|
||||
this case, the application should continue with the initialization
|
||||
of the application user interface before entering the event loop
|
||||
with exec(), as normal.
|
||||
|
||||
The messageReceived() signal will be emitted when the running
|
||||
application receives messages from another instance of the same
|
||||
application. When a message is received it might be helpful to the
|
||||
user to raise the application so that it becomes visible. To
|
||||
facilitate this, QtSingleApplication provides the
|
||||
setActivationWindow() function and the activateWindow() slot.
|
||||
|
||||
If isRunning() returns true, another instance is already
|
||||
running. It may be alerted to the fact that another instance has
|
||||
started by using the sendMessage() function. Also data such as
|
||||
startup parameters (e.g. the name of the file the user wanted this
|
||||
new instance to open) can be passed to the running instance with
|
||||
this function. Then, the application should terminate (or enter
|
||||
client mode).
|
||||
|
||||
If isRunning() returns true, but sendMessage() fails, that is an
|
||||
indication that the running instance is frozen.
|
||||
|
||||
Here's an example that shows how to convert an existing
|
||||
application to use QtSingleApplication. It is very simple and does
|
||||
not make use of all QtSingleApplication's functionality (see the
|
||||
examples for that).
|
||||
|
||||
\code
|
||||
// Original
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MyMainWidget mmw;
|
||||
mmw.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
// Single instance
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QtSingleApplication app(argc, argv);
|
||||
|
||||
if (app.isRunning())
|
||||
return !app.sendMessage(someDataString);
|
||||
|
||||
MyMainWidget mmw;
|
||||
app.setActivationWindow(&mmw);
|
||||
mmw.show();
|
||||
return app.exec();
|
||||
}
|
||||
\endcode
|
||||
|
||||
Once this QtSingleApplication instance is destroyed (normally when
|
||||
the process exits or crashes), when the user next attempts to run the
|
||||
application this instance will not, of course, be encountered. The
|
||||
next instance to call isRunning() or sendMessage() will assume the
|
||||
role as the new running instance.
|
||||
|
||||
For console (non-GUI) applications, QtSingleCoreApplication may be
|
||||
used instead of this class, to avoid the dependency on the QtGui
|
||||
library.
|
||||
|
||||
\sa QtSingleCoreApplication
|
||||
*/
|
||||
|
||||
|
||||
void QtSingleApplication::sysInit(const QString &appId)
|
||||
{
|
||||
actWin = 0;
|
||||
peer = new QtLocalPeer(this, appId);
|
||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a QtSingleApplication object. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||
argv, and \a GUIenabled are passed on to the QAppliation constructor.
|
||||
|
||||
If you are creating a console application (i.e. setting \a
|
||||
GUIenabled to false), you may consider using
|
||||
QtSingleCoreApplication instead.
|
||||
*/
|
||||
|
||||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
||||
: QApplication(argc, argv, GUIenabled)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a QtSingleApplication object with the application
|
||||
identifier \a appId. \a argc and \a argv are passed on to the
|
||||
QAppliation constructor.
|
||||
*/
|
||||
|
||||
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
{
|
||||
sysInit(appId);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a QtSingleApplication object. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||
argv, and \a type are passed on to the QAppliation constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
|
||||
: QApplication(argc, argv, type)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
|
||||
#if defined(Q_WS_X11)
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
||||
and \a cmap are passed on to the QApplication constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, visual, cmap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||
constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, argc, argv, visual, cmap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be \a appId. \a dpy, \a argc, \a
|
||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||
constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, argc, argv, visual, cmap)
|
||||
{
|
||||
sysInit(appId);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
Returns true if another instance of this application is running;
|
||||
otherwise false.
|
||||
|
||||
This function does not find instances of this application that are
|
||||
being run by a different user (on Windows: that are running in
|
||||
another session).
|
||||
|
||||
\sa sendMessage()
|
||||
*/
|
||||
|
||||
bool QtSingleApplication::isRunning()
|
||||
{
|
||||
return peer->isClient();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tries to send the text \a message to the currently running
|
||||
instance. The QtSingleApplication object in the running instance
|
||||
will emit the messageReceived() signal when it receives the
|
||||
message.
|
||||
|
||||
This function returns true if the message has been sent to, and
|
||||
processed by, the current instance. If there is no instance
|
||||
currently running, or if the running instance fails to process the
|
||||
message within \a timeout milliseconds, this function return false.
|
||||
|
||||
\sa isRunning(), messageReceived()
|
||||
*/
|
||||
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
|
||||
{
|
||||
return peer->sendMessage(message, timeout);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the application identifier. Two processes with the same
|
||||
identifier will be regarded as instances of the same application.
|
||||
*/
|
||||
QString QtSingleApplication::id() const
|
||||
{
|
||||
return peer->applicationId();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Sets the activation window of this application to \a aw. The
|
||||
activation window is the widget that will be activated by
|
||||
activateWindow(). This is typically the application's main window.
|
||||
|
||||
If \a activateOnMessage is true (the default), the window will be
|
||||
activated automatically every time a message is received, just prior
|
||||
to the messageReceived() signal being emitted.
|
||||
|
||||
\sa activateWindow(), messageReceived()
|
||||
*/
|
||||
|
||||
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
|
||||
{
|
||||
actWin = aw;
|
||||
if (activateOnMessage)
|
||||
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||
else
|
||||
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the applications activation window if one has been set by
|
||||
calling setActivationWindow(), otherwise returns 0.
|
||||
|
||||
\sa setActivationWindow()
|
||||
*/
|
||||
QWidget* QtSingleApplication::activationWindow() const
|
||||
{
|
||||
return actWin;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
De-minimizes, raises, and activates this application's activation window.
|
||||
This function does nothing if no activation window has been set.
|
||||
|
||||
This is a convenience function to show the user that this
|
||||
application instance has been activated when he has tried to start
|
||||
another instance.
|
||||
|
||||
This function should typically be called in response to the
|
||||
messageReceived() signal. By default, that will happen
|
||||
automatically, if an activation window has been set.
|
||||
|
||||
\sa setActivationWindow(), messageReceived(), initialize()
|
||||
*/
|
||||
void QtSingleApplication::activateWindow()
|
||||
{
|
||||
if (actWin) {
|
||||
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
|
||||
actWin->raise();
|
||||
actWin->activateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\fn void QtSingleApplication::messageReceived(const QString& message)
|
||||
|
||||
This signal is emitted when the current instance receives a \a
|
||||
message from another instance of this application.
|
||||
|
||||
\sa sendMessage(), setActivationWindow(), activateWindow()
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn void QtSingleApplication::initialize(bool dummy = true)
|
||||
|
||||
\obsolete
|
||||
*/
|
@@ -1,84 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
class QtLocalPeer;
|
||||
|
||||
class DLLEXPORT QtSingleApplication : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
||||
QtSingleApplication(const QString &id, int &argc, char **argv);
|
||||
QtSingleApplication(int &argc, char **argv, Type type);
|
||||
#if defined(Q_WS_X11)
|
||||
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
|
||||
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
#endif
|
||||
|
||||
bool isRunning();
|
||||
QString id() const;
|
||||
|
||||
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
|
||||
QWidget* activationWindow() const;
|
||||
|
||||
// Obsolete:
|
||||
void initialize(bool dummy = true)
|
||||
{ isRunning(); Q_UNUSED(dummy) }
|
||||
|
||||
public Q_SLOTS:
|
||||
bool sendMessage(const QString &message, int timeout = 5000);
|
||||
void activateWindow();
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
|
||||
|
||||
private:
|
||||
void sysInit(const QString &appId = QString());
|
||||
QtLocalPeer *peer;
|
||||
QWidget *actWin;
|
||||
};
|
@@ -1,148 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qtsinglecoreapplication.h"
|
||||
#include "qtlocalpeer.h"
|
||||
|
||||
/*!
|
||||
\class QtSingleCoreApplication qtsinglecoreapplication.h
|
||||
\brief A variant of the QtSingleApplication class for non-GUI applications.
|
||||
|
||||
This class is a variant of QtSingleApplication suited for use in
|
||||
console (non-GUI) applications. It is an extension of
|
||||
QCoreApplication (instead of QApplication). It does not require
|
||||
the QtGui library.
|
||||
|
||||
The API and usage is identical to QtSingleApplication, except that
|
||||
functions relating to the "activation window" are not present, for
|
||||
obvious reasons. Please refer to the QtSingleApplication
|
||||
documentation for explanation of the usage.
|
||||
|
||||
A QtSingleCoreApplication instance can communicate to a
|
||||
QtSingleApplication instance if they share the same application
|
||||
id. Hence, this class can be used to create a light-weight
|
||||
command-line tool that sends commands to a GUI application.
|
||||
|
||||
\sa QtSingleApplication
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a QtSingleCoreApplication object. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a argc and \a
|
||||
argv are passed on to the QCoreAppliation constructor.
|
||||
*/
|
||||
|
||||
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
||||
: QCoreApplication(argc, argv)
|
||||
{
|
||||
peer = new QtLocalPeer(this);
|
||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a QtSingleCoreApplication object with the application
|
||||
identifier \a appId. \a argc and \a argv are passed on to the
|
||||
QCoreAppliation constructor.
|
||||
*/
|
||||
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
||||
: QCoreApplication(argc, argv)
|
||||
{
|
||||
peer = new QtLocalPeer(this, appId);
|
||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns true if another instance of this application is running;
|
||||
otherwise false.
|
||||
|
||||
This function does not find instances of this application that are
|
||||
being run by a different user (on Windows: that are running in
|
||||
another session).
|
||||
|
||||
\sa sendMessage()
|
||||
*/
|
||||
|
||||
bool QtSingleCoreApplication::isRunning()
|
||||
{
|
||||
return peer->isClient();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tries to send the text \a message to the currently running
|
||||
instance. The QtSingleCoreApplication object in the running instance
|
||||
will emit the messageReceived() signal when it receives the
|
||||
message.
|
||||
|
||||
This function returns true if the message has been sent to, and
|
||||
processed by, the current instance. If there is no instance
|
||||
currently running, or if the running instance fails to process the
|
||||
message within \a timeout milliseconds, this function return false.
|
||||
|
||||
\sa isRunning(), messageReceived()
|
||||
*/
|
||||
|
||||
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
||||
{
|
||||
return peer->sendMessage(message, timeout);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the application identifier. Two processes with the same
|
||||
identifier will be regarded as instances of the same application.
|
||||
*/
|
||||
|
||||
QString QtSingleCoreApplication::id() const
|
||||
{
|
||||
return peer->applicationId();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
|
||||
|
||||
This signal is emitted when the current instance receives a \a
|
||||
message from another instance of this application.
|
||||
|
||||
\sa sendMessage()
|
||||
*/
|
@@ -1,66 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of a Qt Solutions component.
|
||||
**
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) 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
|
||||
** OWNER 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."
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
class QtLocalPeer;
|
||||
|
||||
class QtSingleCoreApplication : public QCoreApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtSingleCoreApplication(int &argc, char **argv);
|
||||
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
|
||||
|
||||
bool isRunning();
|
||||
QString id() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool sendMessage(const QString &message, int timeout = 5000);
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
|
||||
|
||||
private:
|
||||
QtLocalPeer* peer;
|
||||
};
|
@@ -63,7 +63,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
|
||||
{
|
||||
bool becameSolved = false;
|
||||
{
|
||||
// QMutexLocker lock( &m_mut );
|
||||
QMutexLocker lock( &m_mutex );
|
||||
m_results.append( newresults );
|
||||
qStableSort( m_results.begin(), m_results.end(), Query::resultSorter );
|
||||
|
||||
@@ -101,7 +101,7 @@ void
|
||||
Query::removeResult( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
{
|
||||
// QMutexLocker lock( &m_mut );
|
||||
QMutexLocker lock( &m_mutex );
|
||||
m_results.removeAll( result );
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ Query::onResolvingFinished()
|
||||
QList< result_ptr >
|
||||
Query::results() const
|
||||
{
|
||||
// QMutexLocker lock( &m_mut );
|
||||
QMutexLocker lock( &m_mutex );
|
||||
return m_results;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ Query::results() const
|
||||
unsigned int
|
||||
Query::numResults() const
|
||||
{
|
||||
// QMutexLocker lock( &m_mut );
|
||||
QMutexLocker lock( &m_mutex );
|
||||
return m_results.length();
|
||||
}
|
||||
|
||||
@@ -149,7 +149,18 @@ Query::id() const
|
||||
bool
|
||||
Query::resultSorter( const result_ptr& left, const result_ptr& right )
|
||||
{
|
||||
return left->score() > right->score();
|
||||
const float ls = left->score();
|
||||
const float rs = right->score();
|
||||
|
||||
if ( ls == rs )
|
||||
{
|
||||
if ( !left->collection().isNull() && left->collection()->source()->isLocal() )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return ls > rs;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -116,6 +116,8 @@ private:
|
||||
QString m_track;
|
||||
int m_duration;
|
||||
QString m_resultHint;
|
||||
|
||||
mutable QMutex m_mutex;
|
||||
};
|
||||
|
||||
}; //ns
|
||||
|
@@ -38,7 +38,7 @@ Source::Source( int id, const QString &username )
|
||||
, m_id( id )
|
||||
, m_cc( 0 )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << Q_FUNC_INFO << id << username;
|
||||
|
||||
if ( id == 0 )
|
||||
{
|
||||
@@ -146,6 +146,7 @@ Source::setOnline()
|
||||
{
|
||||
if ( m_online )
|
||||
return;
|
||||
m_online = true;
|
||||
|
||||
// ensure username is in the database
|
||||
DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, m_friendlyname );
|
||||
@@ -153,7 +154,6 @@ Source::setOnline()
|
||||
SLOT( dbLoaded( unsigned int, const QString& ) ) );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
|
||||
m_online = true;
|
||||
emit online();
|
||||
}
|
||||
|
||||
|
@@ -66,29 +66,50 @@ TomahawkSettings::~TomahawkSettings()
|
||||
|
||||
|
||||
QStringList
|
||||
TomahawkSettings::scannerPath() const
|
||||
TomahawkSettings::scannerPaths()
|
||||
{
|
||||
//FIXME: After enough time, remove this hack (and make const)
|
||||
#ifndef TOMAHAWK_HEADLESS
|
||||
return value( "scannerpath", QDesktopServices::storageLocation( QDesktopServices::MusicLocation ) ).toStringList();
|
||||
if( value( "scannerpaths" ).isNull() )
|
||||
setValue( "scannerpaths", value( "scannerpath" ) );
|
||||
return value( "scannerpaths", QDesktopServices::storageLocation( QDesktopServices::MusicLocation ) ).toStringList();
|
||||
#else
|
||||
return value( "scannerpath", "" ).toStringList();
|
||||
if( value( "scannerpaths" ).isNull() )
|
||||
setValue( "scannerpaths", value( "scannerpath" ) );
|
||||
return value( "scannerpaths", "" ).toStringList();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkSettings::setScannerPath( const QStringList& path )
|
||||
TomahawkSettings::setScannerPaths( const QStringList& paths )
|
||||
{
|
||||
setValue( "scannerpath", path );
|
||||
setValue( "scannerpaths", paths );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkSettings::hasScannerPath() const
|
||||
TomahawkSettings::hasScannerPaths() const
|
||||
{
|
||||
return contains( "scannerpath" );
|
||||
//FIXME: After enough time, remove this hack
|
||||
return contains( "scannerpaths" ) || contains( "scannerpath" );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkSettings::watchForChanges() const
|
||||
{
|
||||
return value( "watchForChanges", true ).toBool();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkSettings::setWatchForChanges( bool watch )
|
||||
{
|
||||
setValue( "watchForChanges", watch );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkSettings::setAcceptedLegalWarning( bool accept )
|
||||
{
|
||||
|
@@ -41,9 +41,12 @@ public:
|
||||
void applyChanges() { emit changed(); }
|
||||
|
||||
/// General settings
|
||||
QStringList scannerPath() const; /// QDesktopServices::MusicLocation by default
|
||||
void setScannerPath( const QStringList& path );
|
||||
bool hasScannerPath() const;
|
||||
QStringList scannerPaths(); /// QDesktopServices::MusicLocation by default
|
||||
void setScannerPaths( const QStringList& paths );
|
||||
bool hasScannerPaths() const;
|
||||
|
||||
bool watchForChanges() const;
|
||||
void setWatchForChanges( bool watch );
|
||||
|
||||
bool acceptedLegalWarning() const;
|
||||
void setAcceptedLegalWarning( bool accept );
|
||||
|
@@ -83,7 +83,7 @@ AnimatedSplitter::hide( int index, bool animate )
|
||||
|
||||
emit hidden( w );
|
||||
w->setMinimumHeight( minHeight );
|
||||
qDebug() << "animating to:" << w->height() << "from" << minHeight;
|
||||
// qDebug() << "animating to:" << w->height() << "from" << minHeight;
|
||||
|
||||
m_animateForward = false;
|
||||
if ( animate )
|
||||
|
@@ -31,7 +31,9 @@
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#define FILTER_TIMEOUT 280
|
||||
#define HISTORY_TRACK_ITEMS 50
|
||||
#define HISTORY_PLAYLIST_ITEMS 10
|
||||
#define HISTORY_RESOLVING_TIMEOUT 2500
|
||||
|
||||
|
||||
WelcomeWidget::WelcomeWidget( QWidget* parent )
|
||||
@@ -46,7 +48,10 @@ WelcomeWidget::WelcomeWidget( QWidget* parent )
|
||||
|
||||
m_tracksModel = new PlaylistModel( ui->tracksView );
|
||||
ui->tracksView->setModel( m_tracksModel );
|
||||
m_tracksModel->loadHistory( Tomahawk::source_ptr() );
|
||||
m_tracksModel->loadHistory( Tomahawk::source_ptr(), HISTORY_TRACK_ITEMS );
|
||||
|
||||
m_timer = new QTimer( this );
|
||||
connect( m_timer, SIGNAL( timeout() ), SLOT( checkQueries() ) );
|
||||
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
|
||||
@@ -96,10 +101,25 @@ WelcomeWidget::onSourceAdded( const Tomahawk::source_ptr& source )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WelcomeWidget::checkQueries()
|
||||
{
|
||||
m_timer->stop();
|
||||
m_tracksModel->ensureResolved();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WelcomeWidget::onPlaybackFinished( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
m_tracksModel->insert( 0, query );
|
||||
|
||||
if ( m_tracksModel->trackCount() > HISTORY_TRACK_ITEMS )
|
||||
m_tracksModel->remove( HISTORY_TRACK_ITEMS );
|
||||
|
||||
if ( m_timer->isActive() )
|
||||
m_timer->stop();
|
||||
m_timer->start( HISTORY_RESOLVING_TIMEOUT );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -124,10 +124,13 @@ private slots:
|
||||
void onPlaylistActivated( QListWidgetItem* item );
|
||||
void onPlaybackFinished( const Tomahawk::query_ptr& query );
|
||||
|
||||
void checkQueries();
|
||||
|
||||
private:
|
||||
Ui::WelcomeWidget *ui;
|
||||
|
||||
PlaylistModel* m_tracksModel;
|
||||
QTimer* m_timer;
|
||||
};
|
||||
|
||||
#endif // WELCOMEWIDGET_H
|
||||
|
23
src/main.cpp
23
src/main.cpp
@@ -18,13 +18,16 @@
|
||||
|
||||
#include "tomahawk/tomahawkapp.h"
|
||||
|
||||
#include "kdsingleapplicationguard/kdsingleapplicationguard.h"
|
||||
#include <QTranslator>
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include "tomahawkapp_mac.h"
|
||||
#include </System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers/AppleEvents.h>
|
||||
static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long );
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
|
||||
int
|
||||
main( int argc, char *argv[] )
|
||||
{
|
||||
@@ -36,18 +39,20 @@ main( int argc, char *argv[] )
|
||||
// used for url handler
|
||||
AEEventHandlerUPP h = AEEventHandlerUPP( appleEventHandler );
|
||||
AEInstallEventHandler( 'GURL', 'GURL', h, 0, false );
|
||||
|
||||
#endif
|
||||
try
|
||||
{
|
||||
|
||||
TomahawkApp a( argc, argv );
|
||||
KDSingleApplicationGuard guard( &a, KDSingleApplicationGuard::AutoKillOtherInstances );
|
||||
QObject::connect( &guard, SIGNAL( instanceStarted( KDSingleApplicationGuard::Instance ) ), &a, SLOT( instanceStarted( KDSingleApplicationGuard::Instance ) ) );
|
||||
|
||||
QString locale = QLocale::system().name();
|
||||
|
||||
QTranslator translator;
|
||||
translator.load( QString( ":/lang/tomahawk_" ) + locale );
|
||||
a.installTranslator( &translator );
|
||||
return a.exec();
|
||||
}
|
||||
catch( const std::runtime_error& e )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
static pascal OSErr
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user