mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
added FileDragAndDropTarget class and rewrote all the drag handling code
This commit is contained in:
parent
6d2d246768
commit
60e1be176e
44 changed files with 1182 additions and 829 deletions
|
|
@ -33,7 +33,7 @@
|
|||
#include <dlfcn.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1108,8 +1108,8 @@ public:
|
|||
data[index++] = newIcon.getPixelAt (x, y).getARGB();
|
||||
|
||||
XChangeProperty (display, windowH,
|
||||
XInternAtom (display, "_NET_WM_ICON", False),
|
||||
XA_CARDINAL, 32, PropModeReplace,
|
||||
XInternAtom (display, "_NET_WM_ICON", False),
|
||||
XA_CARDINAL, 32, PropModeReplace,
|
||||
(unsigned char*) data, dataSize);
|
||||
|
||||
XSync (display, False);
|
||||
|
|
@ -1542,7 +1542,7 @@ public:
|
|||
|
||||
case ClientMessage:
|
||||
{
|
||||
XClientMessageEvent* clientMsg = (XClientMessageEvent*) &event->xclient;
|
||||
const XClientMessageEvent* const clientMsg = (const XClientMessageEvent*) &event->xclient;
|
||||
|
||||
if (clientMsg->message_type == wm_Protocols && clientMsg->format == 32)
|
||||
{
|
||||
|
|
@ -1592,14 +1592,14 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
case SelectionClear:
|
||||
case SelectionRequest:
|
||||
break;
|
||||
|
||||
case SelectionNotify:
|
||||
handleDragAndDropSelection (event);
|
||||
break;
|
||||
|
||||
case SelectionClear:
|
||||
case SelectionRequest:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2219,6 +2219,7 @@ private:
|
|||
//==============================================================================
|
||||
void resetDragAndDrop()
|
||||
{
|
||||
dragAndDropFiles.clear();
|
||||
lastDropX = lastDropY = -1;
|
||||
dragAndDropCurrentMimeType = 0;
|
||||
dragAndDropSourceWindow = 0;
|
||||
|
|
@ -2242,8 +2243,6 @@ private:
|
|||
zerostruct (msg);
|
||||
msg.message_type = XA_XdndStatus;
|
||||
msg.data.l[1] = (acceptDrop ? 1 : 0) | 2; // 2 indicates that we want to receive position messages
|
||||
//msg.data.l[2] = (0 << 16) + 0;
|
||||
//msg.data.l[3] = (0 << 16) + 0;
|
||||
msg.data.l[4] = dropAction;
|
||||
|
||||
sendDragAndDropMessage (msg);
|
||||
|
|
@ -2270,7 +2269,11 @@ private:
|
|||
if ((clientMsg->data.l[1] & 1) == 0)
|
||||
{
|
||||
sendDragAndDropLeave();
|
||||
return;
|
||||
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
handleFileDragExit (dragAndDropFiles);
|
||||
|
||||
dragAndDropFiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2303,83 +2306,33 @@ private:
|
|||
}
|
||||
|
||||
sendDragAndDropStatus (true, targetAction);
|
||||
|
||||
if (dragAndDropFiles.size() == 0)
|
||||
updateDraggedFileList (clientMsg);
|
||||
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
handleFileDragMove (dragAndDropFiles, dropX, dropY);
|
||||
}
|
||||
}
|
||||
|
||||
void handleDragAndDropDrop (const XClientMessageEvent* const clientMsg)
|
||||
{
|
||||
if (dragAndDropSourceWindow != None
|
||||
&& dragAndDropCurrentMimeType != 0)
|
||||
{
|
||||
dragAndDropTimestamp = clientMsg->data.l[2];
|
||||
|
||||
XConvertSelection (display,
|
||||
XA_XdndSelection,
|
||||
dragAndDropCurrentMimeType,
|
||||
XA_JXSelectionWindowProperty,
|
||||
windowH,
|
||||
dragAndDropTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void handleDragAndDropSelection (const XEvent* const evt)
|
||||
{
|
||||
StringArray files;
|
||||
|
||||
if (evt->xselection.property != 0)
|
||||
{
|
||||
StringArray lines;
|
||||
|
||||
{
|
||||
MemoryBlock dropData;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Atom actual;
|
||||
uint8* data = 0;
|
||||
unsigned long count = 0, remaining = 0;
|
||||
int format = 0;
|
||||
|
||||
if (XGetWindowProperty (display, evt->xany.window, evt->xselection.property,
|
||||
dropData.getSize() / 4, 65536, 1, AnyPropertyType, &actual,
|
||||
&format, &count, &remaining, &data) == Success)
|
||||
{
|
||||
dropData.append (data, count * format / 8);
|
||||
XFree (data);
|
||||
|
||||
if (remaining == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
XFree (data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lines.addLines (dropData.toString());
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
const String filename (URL::removeEscapeChars (lines[i].fromFirstOccurrenceOf (T("file://"), false, true)));
|
||||
|
||||
if (filename.isNotEmpty())
|
||||
files.add (filename);
|
||||
}
|
||||
}
|
||||
if (dragAndDropFiles.size() == 0)
|
||||
updateDraggedFileList (clientMsg);
|
||||
|
||||
const StringArray files (dragAndDropFiles);
|
||||
const int lastX = lastDropX, lastY = lastDropY;
|
||||
|
||||
sendDragAndDropFinish();
|
||||
resetDragAndDrop();
|
||||
|
||||
if (files.size() > 0)
|
||||
handleFilesDropped (lastX, lastY, files);
|
||||
handleFileDragDrop (files, lastX, lastY);
|
||||
}
|
||||
|
||||
void handleDragAndDropEnter (const XClientMessageEvent* const clientMsg)
|
||||
{
|
||||
dragAndDropFiles.clear();
|
||||
srcMimeTypeAtomList.clear();
|
||||
|
||||
dragAndDropCurrentMimeType = 0;
|
||||
|
|
@ -2432,8 +2385,75 @@ private:
|
|||
for (int j = 0; j < numElementsInArray (allowedMimeTypeAtoms); ++j)
|
||||
if (srcMimeTypeAtomList[i] == allowedMimeTypeAtoms[j])
|
||||
dragAndDropCurrentMimeType = allowedMimeTypeAtoms[j];
|
||||
|
||||
handleDragAndDropPosition (clientMsg);
|
||||
}
|
||||
|
||||
void handleDragAndDropSelection (const XEvent* const evt)
|
||||
{
|
||||
dragAndDropFiles.clear();
|
||||
|
||||
if (evt->xselection.property != 0)
|
||||
{
|
||||
StringArray lines;
|
||||
|
||||
{
|
||||
MemoryBlock dropData;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Atom actual;
|
||||
uint8* data = 0;
|
||||
unsigned long count = 0, remaining = 0;
|
||||
int format = 0;
|
||||
|
||||
if (XGetWindowProperty (display, evt->xany.window, evt->xselection.property,
|
||||
dropData.getSize() / 4, 65536, 1, AnyPropertyType, &actual,
|
||||
&format, &count, &remaining, &data) == Success)
|
||||
{
|
||||
dropData.append (data, count * format / 8);
|
||||
XFree (data);
|
||||
|
||||
if (remaining == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
XFree (data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lines.addLines (dropData.toString());
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
dragAndDropFiles.add (URL::removeEscapeChars (lines[i].fromFirstOccurrenceOf (T("file://"), false, true)));
|
||||
|
||||
dragAndDropFiles.trim();
|
||||
dragAndDropFiles.removeEmptyStrings();
|
||||
}
|
||||
}
|
||||
|
||||
void updateDraggedFileList (const XClientMessageEvent* const clientMsg)
|
||||
{
|
||||
dragAndDropFiles.clear();
|
||||
|
||||
if (dragAndDropSourceWindow != None
|
||||
&& dragAndDropCurrentMimeType != 0)
|
||||
{
|
||||
dragAndDropTimestamp = clientMsg->data.l[2];
|
||||
|
||||
XConvertSelection (display,
|
||||
XA_XdndSelection,
|
||||
dragAndDropCurrentMimeType,
|
||||
XA_JXSelectionWindowProperty,
|
||||
windowH,
|
||||
dragAndDropTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
StringArray dragAndDropFiles;
|
||||
int dragAndDropTimestamp, lastDropX, lastDropY;
|
||||
|
||||
Atom XA_OtherMime, dragAndDropCurrentMimeType;
|
||||
|
|
|
|||
|
|
@ -654,6 +654,7 @@
|
|||
84FC31BB09B74A5C00B75141 /* juce_WildcardFileFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FC31A909B74A5C00B75141 /* juce_WildcardFileFilter.h */; };
|
||||
84FC31BE09B74A7700B75141 /* juce_BorderSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FC31BC09B74A7700B75141 /* juce_BorderSize.cpp */; };
|
||||
84FC31BF09B74A7700B75141 /* juce_BorderSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FC31BD09B74A7700B75141 /* juce_BorderSize.h */; };
|
||||
84FED3C90CAA96DA00003997 /* juce_FileDragAndDropTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FED3C80CAA96DA00003997 /* juce_FileDragAndDropTarget.h */; };
|
||||
84FFAF2B0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */; };
|
||||
84FFAF2C0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
|
@ -1309,6 +1310,7 @@
|
|||
84FC31A909B74A5C00B75141 /* juce_WildcardFileFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_WildcardFileFilter.h; path = filebrowser/juce_WildcardFileFilter.h; sourceTree = "<group>"; };
|
||||
84FC31BC09B74A7700B75141 /* juce_BorderSize.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = juce_BorderSize.cpp; sourceTree = "<group>"; };
|
||||
84FC31BD09B74A7700B75141 /* juce_BorderSize.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_BorderSize.h; sourceTree = "<group>"; };
|
||||
84FED3C80CAA96DA00003997 /* juce_FileDragAndDropTarget.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_FileDragAndDropTarget.h; sourceTree = "<group>"; };
|
||||
84FFAF290C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileSearchPathListComponent.cpp; path = filebrowser/juce_FileSearchPathListComponent.cpp; sourceTree = "<group>"; };
|
||||
84FFAF2A0C6C8F2B009F6E72 /* juce_FileSearchPathListComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_FileSearchPathListComponent.h; path = filebrowser/juce_FileSearchPathListComponent.h; sourceTree = "<group>"; };
|
||||
D2AAC046055464E500DB518D /* libjucedebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjucedebug.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -1785,6 +1787,7 @@
|
|||
84A488D408A22E4900752A2B /* juce_DragAndDropContainer.cpp */,
|
||||
84A488D508A22E4900752A2B /* juce_DragAndDropContainer.h */,
|
||||
84A488D608A22E4900752A2B /* juce_DragAndDropTarget.h */,
|
||||
84FED3C80CAA96DA00003997 /* juce_FileDragAndDropTarget.h */,
|
||||
84F593B009855693008153BA /* juce_LassoComponent.h */,
|
||||
84A488D708A22E4900752A2B /* juce_MouseCursor.cpp */,
|
||||
84A488D808A22E4900752A2B /* juce_MouseCursor.h */,
|
||||
|
|
@ -2766,6 +2769,7 @@
|
|||
84BC4E2D0C8DD38C00FA249B /* juce_AudioProcessorEditor.h in Headers */,
|
||||
84BC4E2E0C8DD38C00FA249B /* juce_AudioProcessorListener.h in Headers */,
|
||||
84BC4E300C8DD38C00FA249B /* juce_GenericAudioProcessorEditor.h in Headers */,
|
||||
84FED3C90CAA96DA00003997 /* juce_FileDragAndDropTarget.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,386 +1,386 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
JUCE 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 JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/threads/juce_CriticalSection.h"
|
||||
#include "../../../src/juce_core/threads/juce_WaitableEvent.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/threads/juce_Process.h"
|
||||
#include "../../../src/juce_core/threads/juce_InterProcessLock.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/files/juce_File.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
CriticalSection::CriticalSection() throw()
|
||||
{
|
||||
pthread_mutexattr_t atts;
|
||||
pthread_mutexattr_init (&atts);
|
||||
pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init (&internal, &atts);
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection() throw()
|
||||
{
|
||||
pthread_mutex_destroy (&internal);
|
||||
}
|
||||
|
||||
void CriticalSection::enter() const throw()
|
||||
{
|
||||
pthread_mutex_lock (&internal);
|
||||
}
|
||||
|
||||
bool CriticalSection::tryEnter() const throw()
|
||||
{
|
||||
return pthread_mutex_trylock (&internal) == 0;
|
||||
}
|
||||
|
||||
void CriticalSection::exit() const throw()
|
||||
{
|
||||
pthread_mutex_unlock (&internal);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct EventStruct
|
||||
{
|
||||
pthread_cond_t condition;
|
||||
pthread_mutex_t mutex;
|
||||
bool triggered;
|
||||
};
|
||||
|
||||
WaitableEvent::WaitableEvent() throw()
|
||||
{
|
||||
EventStruct* const es = new EventStruct();
|
||||
es->triggered = false;
|
||||
|
||||
pthread_cond_init (&es->condition, 0);
|
||||
pthread_mutex_init (&es->mutex, 0);
|
||||
|
||||
internal = es;
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_cond_destroy (&es->condition);
|
||||
pthread_mutex_destroy (&es->mutex);
|
||||
|
||||
delete es;
|
||||
}
|
||||
|
||||
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
bool ok = true;
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
|
||||
if (! es->triggered)
|
||||
{
|
||||
if (timeOutMillisecs < 0)
|
||||
{
|
||||
pthread_cond_wait (&es->condition, &es->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec time;
|
||||
time.tv_sec = timeOutMillisecs / 1000;
|
||||
time.tv_nsec = (timeOutMillisecs % 1000) * 1000000;
|
||||
pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time);
|
||||
}
|
||||
|
||||
ok = es->triggered;
|
||||
}
|
||||
|
||||
es->triggered = false;
|
||||
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
es->triggered = true;
|
||||
pthread_cond_signal (&es->condition);
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
}
|
||||
|
||||
void WaitableEvent::reset() const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
es->triggered = false;
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JUCE_API juce_threadEntryPoint (void*);
|
||||
|
||||
void* threadEntryProc (void* userData) throw()
|
||||
{
|
||||
juce_threadEntryPoint (userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* juce_createThread (void* userData) throw()
|
||||
{
|
||||
pthread_t handle = 0;
|
||||
|
||||
if (pthread_create (&handle, 0, threadEntryProc, userData) == 0)
|
||||
{
|
||||
pthread_detach (handle);
|
||||
return (void*) handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void juce_killThread (void* handle) throw()
|
||||
{
|
||||
if (handle != 0)
|
||||
pthread_cancel ((pthread_t) handle);
|
||||
}
|
||||
|
||||
void juce_setCurrentThreadName (const String& /*name*/) throw()
|
||||
{
|
||||
}
|
||||
|
||||
int Thread::getCurrentThreadId() throw()
|
||||
{
|
||||
return (int) pthread_self();
|
||||
}
|
||||
|
||||
void juce_setThreadPriority (void* handle, int priority) throw()
|
||||
{
|
||||
if (handle == 0)
|
||||
handle = (void*) pthread_self();
|
||||
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
pthread_getschedparam ((pthread_t) handle, &policy, ¶m);
|
||||
param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11);
|
||||
pthread_setschedparam ((pthread_t) handle, policy, ¶m);
|
||||
}
|
||||
|
||||
void Thread::yield() throw()
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw()
|
||||
{
|
||||
// xxx
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
|
||||
{
|
||||
struct timespec time;
|
||||
time.tv_sec = millisecs / 1000;
|
||||
time.tv_nsec = (millisecs % 1000) * 1000000;
|
||||
nanosleep (&time, 0);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool JUCE_CALLTYPE juce_isRunningUnderDebugger() throw()
|
||||
{
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
testResult = (ptrace (PT_TRACE_ME, 0, 0, 0) < 0) ? 1 : -1;
|
||||
|
||||
if (testResult < 0)
|
||||
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||
}
|
||||
|
||||
return testResult > 0;
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
void Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
ExitToShell();
|
||||
}
|
||||
|
||||
void Process::setPriority (ProcessPriority p)
|
||||
{
|
||||
// xxx
|
||||
}
|
||||
|
||||
void* Process::loadDynamicLibrary (const String& name)
|
||||
{
|
||||
// xxx needs to use bundles
|
||||
|
||||
FSSpec fs;
|
||||
if (PlatformUtilities::makeFSSpecFromPath (&fs, name))
|
||||
{
|
||||
CFragConnectionID connID;
|
||||
Ptr mainPtr;
|
||||
Str255 errorMessage;
|
||||
Str63 nm;
|
||||
PlatformUtilities::copyToStr63 (nm, name);
|
||||
|
||||
const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage);
|
||||
if (err == noErr)
|
||||
return (void*)connID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Process::freeDynamicLibrary (void* handle)
|
||||
{
|
||||
if (handle != 0)
|
||||
CloseConnection ((CFragConnectionID*)&handle);
|
||||
}
|
||||
|
||||
void* Process::getProcedureEntryPoint (void* h, const String& procedureName)
|
||||
{
|
||||
if (h != 0)
|
||||
{
|
||||
CFragSymbolClass cl;
|
||||
Ptr ptr;
|
||||
Str255 name;
|
||||
PlatformUtilities::copyToStr255 (name, procedureName);
|
||||
|
||||
if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
InterProcessLock::InterProcessLock (const String& name_) throw()
|
||||
: internal (0),
|
||||
name (name_),
|
||||
reentrancyLevel (0)
|
||||
{
|
||||
const File tempDir (File::getSpecialLocation (File::tempDirectory));
|
||||
const File temp (tempDir.getChildFile (name));
|
||||
temp.create();
|
||||
|
||||
internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY);
|
||||
}
|
||||
|
||||
InterProcessLock::~InterProcessLock() throw()
|
||||
{
|
||||
while (reentrancyLevel > 0)
|
||||
this->exit();
|
||||
|
||||
close ((int) internal);
|
||||
}
|
||||
|
||||
bool InterProcessLock::enter (const int timeOutMillisecs) throw()
|
||||
{
|
||||
if (internal == 0)
|
||||
return false;
|
||||
|
||||
if (reentrancyLevel != 0)
|
||||
return true;
|
||||
|
||||
if (timeOutMillisecs <= 0)
|
||||
{
|
||||
if (flock ((int) internal,
|
||||
timeOutMillisecs < 0 ? LOCK_EX
|
||||
: (LOCK_EX | LOCK_NB)) == 0)
|
||||
{
|
||||
++reentrancyLevel;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0)
|
||||
{
|
||||
++reentrancyLevel;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Time::currentTimeMillis() >= endTime)
|
||||
break;
|
||||
|
||||
Thread::sleep (10);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InterProcessLock::exit() throw()
|
||||
{
|
||||
if (reentrancyLevel > 0 && internal != 0)
|
||||
{
|
||||
--reentrancyLevel;
|
||||
|
||||
const int result = flock ((int) internal, LOCK_UN);
|
||||
(void) result;
|
||||
jassert (result == 0);
|
||||
}
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
JUCE 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 JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/threads/juce_CriticalSection.h"
|
||||
#include "../../../src/juce_core/threads/juce_WaitableEvent.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/threads/juce_Process.h"
|
||||
#include "../../../src/juce_core/threads/juce_InterProcessLock.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/files/juce_File.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
CriticalSection::CriticalSection() throw()
|
||||
{
|
||||
pthread_mutexattr_t atts;
|
||||
pthread_mutexattr_init (&atts);
|
||||
pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init (&internal, &atts);
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection() throw()
|
||||
{
|
||||
pthread_mutex_destroy (&internal);
|
||||
}
|
||||
|
||||
void CriticalSection::enter() const throw()
|
||||
{
|
||||
pthread_mutex_lock (&internal);
|
||||
}
|
||||
|
||||
bool CriticalSection::tryEnter() const throw()
|
||||
{
|
||||
return pthread_mutex_trylock (&internal) == 0;
|
||||
}
|
||||
|
||||
void CriticalSection::exit() const throw()
|
||||
{
|
||||
pthread_mutex_unlock (&internal);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct EventStruct
|
||||
{
|
||||
pthread_cond_t condition;
|
||||
pthread_mutex_t mutex;
|
||||
bool triggered;
|
||||
};
|
||||
|
||||
WaitableEvent::WaitableEvent() throw()
|
||||
{
|
||||
EventStruct* const es = new EventStruct();
|
||||
es->triggered = false;
|
||||
|
||||
pthread_cond_init (&es->condition, 0);
|
||||
pthread_mutex_init (&es->mutex, 0);
|
||||
|
||||
internal = es;
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_cond_destroy (&es->condition);
|
||||
pthread_mutex_destroy (&es->mutex);
|
||||
|
||||
delete es;
|
||||
}
|
||||
|
||||
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
bool ok = true;
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
|
||||
if (! es->triggered)
|
||||
{
|
||||
if (timeOutMillisecs < 0)
|
||||
{
|
||||
pthread_cond_wait (&es->condition, &es->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec time;
|
||||
time.tv_sec = timeOutMillisecs / 1000;
|
||||
time.tv_nsec = (timeOutMillisecs % 1000) * 1000000;
|
||||
pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time);
|
||||
}
|
||||
|
||||
ok = es->triggered;
|
||||
}
|
||||
|
||||
es->triggered = false;
|
||||
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
es->triggered = true;
|
||||
pthread_cond_signal (&es->condition);
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
}
|
||||
|
||||
void WaitableEvent::reset() const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
es->triggered = false;
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JUCE_API juce_threadEntryPoint (void*);
|
||||
|
||||
void* threadEntryProc (void* userData) throw()
|
||||
{
|
||||
juce_threadEntryPoint (userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* juce_createThread (void* userData) throw()
|
||||
{
|
||||
pthread_t handle = 0;
|
||||
|
||||
if (pthread_create (&handle, 0, threadEntryProc, userData) == 0)
|
||||
{
|
||||
pthread_detach (handle);
|
||||
return (void*) handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void juce_killThread (void* handle) throw()
|
||||
{
|
||||
if (handle != 0)
|
||||
pthread_cancel ((pthread_t) handle);
|
||||
}
|
||||
|
||||
void juce_setCurrentThreadName (const String& /*name*/) throw()
|
||||
{
|
||||
}
|
||||
|
||||
int Thread::getCurrentThreadId() throw()
|
||||
{
|
||||
return (int) pthread_self();
|
||||
}
|
||||
|
||||
void juce_setThreadPriority (void* handle, int priority) throw()
|
||||
{
|
||||
if (handle == 0)
|
||||
handle = (void*) pthread_self();
|
||||
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
pthread_getschedparam ((pthread_t) handle, &policy, ¶m);
|
||||
param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11);
|
||||
pthread_setschedparam ((pthread_t) handle, policy, ¶m);
|
||||
}
|
||||
|
||||
void Thread::yield() throw()
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw()
|
||||
{
|
||||
// xxx
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
|
||||
{
|
||||
struct timespec time;
|
||||
time.tv_sec = millisecs / 1000;
|
||||
time.tv_nsec = (millisecs % 1000) * 1000000;
|
||||
nanosleep (&time, 0);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool JUCE_CALLTYPE juce_isRunningUnderDebugger() throw()
|
||||
{
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
testResult = (ptrace (PT_TRACE_ME, 0, 0, 0) < 0) ? 1 : -1;
|
||||
|
||||
if (testResult < 0)
|
||||
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||
}
|
||||
|
||||
return testResult > 0;
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
void Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse
|
||||
}
|
||||
|
||||
void Process::terminate()
|
||||
{
|
||||
ExitToShell();
|
||||
}
|
||||
|
||||
void Process::setPriority (ProcessPriority p)
|
||||
{
|
||||
// xxx
|
||||
}
|
||||
|
||||
void* Process::loadDynamicLibrary (const String& name)
|
||||
{
|
||||
// xxx needs to use bundles
|
||||
|
||||
FSSpec fs;
|
||||
if (PlatformUtilities::makeFSSpecFromPath (&fs, name))
|
||||
{
|
||||
CFragConnectionID connID;
|
||||
Ptr mainPtr;
|
||||
Str255 errorMessage;
|
||||
Str63 nm;
|
||||
PlatformUtilities::copyToStr63 (nm, name);
|
||||
|
||||
const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage);
|
||||
if (err == noErr)
|
||||
return (void*)connID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Process::freeDynamicLibrary (void* handle)
|
||||
{
|
||||
if (handle != 0)
|
||||
CloseConnection ((CFragConnectionID*)&handle);
|
||||
}
|
||||
|
||||
void* Process::getProcedureEntryPoint (void* h, const String& procedureName)
|
||||
{
|
||||
if (h != 0)
|
||||
{
|
||||
CFragSymbolClass cl;
|
||||
Ptr ptr;
|
||||
Str255 name;
|
||||
PlatformUtilities::copyToStr255 (name, procedureName);
|
||||
|
||||
if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
InterProcessLock::InterProcessLock (const String& name_) throw()
|
||||
: internal (0),
|
||||
name (name_),
|
||||
reentrancyLevel (0)
|
||||
{
|
||||
const File tempDir (File::getSpecialLocation (File::tempDirectory));
|
||||
const File temp (tempDir.getChildFile (name));
|
||||
temp.create();
|
||||
|
||||
internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY);
|
||||
}
|
||||
|
||||
InterProcessLock::~InterProcessLock() throw()
|
||||
{
|
||||
while (reentrancyLevel > 0)
|
||||
this->exit();
|
||||
|
||||
close ((int) internal);
|
||||
}
|
||||
|
||||
bool InterProcessLock::enter (const int timeOutMillisecs) throw()
|
||||
{
|
||||
if (internal == 0)
|
||||
return false;
|
||||
|
||||
if (reentrancyLevel != 0)
|
||||
return true;
|
||||
|
||||
if (timeOutMillisecs <= 0)
|
||||
{
|
||||
if (flock ((int) internal,
|
||||
timeOutMillisecs < 0 ? LOCK_EX
|
||||
: (LOCK_EX | LOCK_NB)) == 0)
|
||||
{
|
||||
++reentrancyLevel;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0)
|
||||
{
|
||||
++reentrancyLevel;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Time::currentTimeMillis() >= endTime)
|
||||
break;
|
||||
|
||||
Thread::sleep (10);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InterProcessLock::exit() throw()
|
||||
{
|
||||
if (reentrancyLevel > 0 && internal != 0)
|
||||
{
|
||||
--reentrancyLevel;
|
||||
|
||||
const int result = flock ((int) internal, LOCK_UN);
|
||||
(void) result;
|
||||
jassert (result == 0);
|
||||
}
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -835,6 +835,7 @@ public:
|
|||
private:
|
||||
EventHandlerRef eventHandlerRef;
|
||||
bool fullScreen, isSharedWindow, isCompositingWindow;
|
||||
StringArray dragAndDropFiles;
|
||||
|
||||
//==============================================================================
|
||||
class RepaintManager : public Timer
|
||||
|
|
@ -996,106 +997,6 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
OSStatus handleWindowClassEvent (EventRef theEvent)
|
||||
{
|
||||
switch (GetEventKind (theEvent))
|
||||
{
|
||||
case kEventWindowBoundsChanged:
|
||||
resizeViewToFitWindow();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowBoundsChanging:
|
||||
if ((styleFlags & (windowIsResizable | windowHasTitleBar)) == (windowIsResizable | windowHasTitleBar))
|
||||
{
|
||||
UInt32 atts = 0;
|
||||
GetEventParameter (theEvent, kEventParamAttributes, typeUInt32,
|
||||
0, sizeof (UInt32), 0, &atts);
|
||||
|
||||
if ((atts & (kWindowBoundsChangeUserDrag | kWindowBoundsChangeUserResize)) != 0)
|
||||
{
|
||||
if (component->isCurrentlyBlockedByAnotherModalComponent())
|
||||
{
|
||||
Component* const modal = Component::getCurrentlyModalComponent();
|
||||
if (modal != 0)
|
||||
modal->inputAttemptWhenModal();
|
||||
}
|
||||
|
||||
if ((atts & kWindowBoundsChangeUserResize) != 0
|
||||
&& constrainer != 0 && ! isSharedWindow)
|
||||
{
|
||||
Rect current;
|
||||
GetEventParameter (theEvent, kEventParamCurrentBounds, typeQDRectangle,
|
||||
0, sizeof (Rect), 0, ¤t);
|
||||
|
||||
int x = current.left;
|
||||
int y = current.top;
|
||||
int w = current.right - current.left;
|
||||
int h = current.bottom - current.top;
|
||||
|
||||
const Rectangle currentRect (getComponent()->getBounds());
|
||||
|
||||
constrainer->checkBounds (x, y, w, h, currentRect,
|
||||
Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(),
|
||||
y != currentRect.getY() && y + h == currentRect.getBottom(),
|
||||
x != currentRect.getX() && x + w == currentRect.getRight(),
|
||||
y == currentRect.getY() && y + h != currentRect.getBottom(),
|
||||
x == currentRect.getX() && x + w != currentRect.getRight());
|
||||
|
||||
current.left = x;
|
||||
current.top = y;
|
||||
current.right = x + w;
|
||||
current.bottom = y + h;
|
||||
|
||||
SetEventParameter (theEvent, kEventParamCurrentBounds, typeQDRectangle,
|
||||
sizeof (Rect), ¤t);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kEventWindowFocusAcquired:
|
||||
keysCurrentlyDown.clear();
|
||||
|
||||
if ((! isSharedWindow) || HIViewSubtreeContainsFocus (viewRef))
|
||||
viewFocusGain();
|
||||
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowFocusRelinquish:
|
||||
keysCurrentlyDown.clear();
|
||||
viewFocusLoss();
|
||||
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowCollapsed:
|
||||
minimisedWindows.addIfNotAlreadyThere (windowRef);
|
||||
handleMovedOrResized();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowExpanded:
|
||||
minimisedWindows.removeValue (windowRef);
|
||||
handleMovedOrResized();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowShown:
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowClose:
|
||||
if (isSharedWindow)
|
||||
break; // break to let the OS delete the window
|
||||
|
||||
handleUserClosingWindow();
|
||||
return noErr; // avoids letting the OS to delete the window, we'll do that ourselves.
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
OSStatus handleKeyEvent (EventRef theEvent, juce_wchar textCharacter)
|
||||
{
|
||||
updateModifiers (theEvent);
|
||||
|
|
@ -1200,6 +1101,7 @@ public:
|
|||
return handleKeyEvent (originalEvent, (juce_wchar) uc);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OSStatus handleMouseEvent (EventHandlerCallRef callRef, EventRef theEvent)
|
||||
{
|
||||
MouseCheckTimer::getInstance()->moved (this);
|
||||
|
|
@ -1318,19 +1220,57 @@ public:
|
|||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus handleDragAndDrop (EventRef theEvent)
|
||||
//==============================================================================
|
||||
void doDragDropEnter (EventRef theEvent)
|
||||
{
|
||||
updateDragAndDropFileList (theEvent);
|
||||
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
{
|
||||
int x, y;
|
||||
component->getMouseXYRelative (x, y);
|
||||
handleFileDragMove (dragAndDropFiles, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void doDragDropMove (EventRef theEvent)
|
||||
{
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
{
|
||||
int x, y;
|
||||
component->getMouseXYRelative (x, y);
|
||||
handleFileDragMove (dragAndDropFiles, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void doDragDropExit (EventRef theEvent)
|
||||
{
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
handleFileDragExit (dragAndDropFiles);
|
||||
}
|
||||
|
||||
void doDragDrop (EventRef theEvent)
|
||||
{
|
||||
updateDragAndDropFileList (theEvent);
|
||||
|
||||
if (dragAndDropFiles.size() > 0)
|
||||
{
|
||||
int x, y;
|
||||
component->getMouseXYRelative (x, y);
|
||||
handleFileDragDrop (dragAndDropFiles, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void updateDragAndDropFileList (EventRef theEvent)
|
||||
{
|
||||
dragAndDropFiles.clear();
|
||||
|
||||
DragRef dragRef;
|
||||
if (GetEventParameter (theEvent, kEventParamDragRef, typeDragRef, 0, sizeof (dragRef), 0, &dragRef) == noErr)
|
||||
{
|
||||
int mx, my;
|
||||
component->getMouseXYRelative (mx, my);
|
||||
|
||||
UInt16 numItems = 0;
|
||||
if (CountDragItems (dragRef, &numItems) == noErr)
|
||||
{
|
||||
StringArray filenames;
|
||||
|
||||
for (int i = 0; i < (int) numItems; ++i)
|
||||
{
|
||||
DragItemRef ref;
|
||||
|
|
@ -1354,7 +1294,7 @@ public:
|
|||
const String path (PlatformUtilities::makePathFromFSRef (&fsref));
|
||||
|
||||
if (path.isNotEmpty())
|
||||
filenames.add (path);
|
||||
dragAndDropFiles.add (path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1363,17 +1303,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
filenames.trim();
|
||||
filenames.removeEmptyStrings();
|
||||
|
||||
if (filenames.size() > 0)
|
||||
handleFilesDropped (mx, my, filenames);
|
||||
dragAndDropFiles.trim();
|
||||
dragAndDropFiles.removeEmptyStrings();
|
||||
}
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void resizeViewToFitWindow()
|
||||
{
|
||||
HIRect r;
|
||||
|
|
@ -1403,6 +1339,7 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OSStatus hiViewDraw (EventRef theEvent)
|
||||
{
|
||||
CGContextRef context = 0;
|
||||
|
|
@ -1500,16 +1437,103 @@ public:
|
|||
return noErr;
|
||||
}
|
||||
|
||||
static pascal OSStatus handleWindowEvent (EventHandlerCallRef callRef, EventRef theEvent, void* userData)
|
||||
//==============================================================================
|
||||
OSStatus handleWindowClassEvent (EventRef theEvent)
|
||||
{
|
||||
MessageManager::delayWaitCursor();
|
||||
switch (GetEventKind (theEvent))
|
||||
{
|
||||
case kEventWindowBoundsChanged:
|
||||
resizeViewToFitWindow();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
HIViewComponentPeer* const peer = (HIViewComponentPeer*) userData;
|
||||
case kEventWindowBoundsChanging:
|
||||
if ((styleFlags & (windowIsResizable | windowHasTitleBar)) == (windowIsResizable | windowHasTitleBar))
|
||||
{
|
||||
UInt32 atts = 0;
|
||||
GetEventParameter (theEvent, kEventParamAttributes, typeUInt32,
|
||||
0, sizeof (UInt32), 0, &atts);
|
||||
|
||||
const MessageManagerLock messLock;
|
||||
if ((atts & (kWindowBoundsChangeUserDrag | kWindowBoundsChangeUserResize)) != 0)
|
||||
{
|
||||
if (component->isCurrentlyBlockedByAnotherModalComponent())
|
||||
{
|
||||
Component* const modal = Component::getCurrentlyModalComponent();
|
||||
if (modal != 0)
|
||||
modal->inputAttemptWhenModal();
|
||||
}
|
||||
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
return peer->handleWindowEventForPeer (callRef, theEvent);
|
||||
if ((atts & kWindowBoundsChangeUserResize) != 0
|
||||
&& constrainer != 0 && ! isSharedWindow)
|
||||
{
|
||||
Rect current;
|
||||
GetEventParameter (theEvent, kEventParamCurrentBounds, typeQDRectangle,
|
||||
0, sizeof (Rect), 0, ¤t);
|
||||
|
||||
int x = current.left;
|
||||
int y = current.top;
|
||||
int w = current.right - current.left;
|
||||
int h = current.bottom - current.top;
|
||||
|
||||
const Rectangle currentRect (getComponent()->getBounds());
|
||||
|
||||
constrainer->checkBounds (x, y, w, h, currentRect,
|
||||
Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(),
|
||||
y != currentRect.getY() && y + h == currentRect.getBottom(),
|
||||
x != currentRect.getX() && x + w == currentRect.getRight(),
|
||||
y == currentRect.getY() && y + h != currentRect.getBottom(),
|
||||
x == currentRect.getX() && x + w != currentRect.getRight());
|
||||
|
||||
current.left = x;
|
||||
current.top = y;
|
||||
current.right = x + w;
|
||||
current.bottom = y + h;
|
||||
|
||||
SetEventParameter (theEvent, kEventParamCurrentBounds, typeQDRectangle,
|
||||
sizeof (Rect), ¤t);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kEventWindowFocusAcquired:
|
||||
keysCurrentlyDown.clear();
|
||||
|
||||
if ((! isSharedWindow) || HIViewSubtreeContainsFocus (viewRef))
|
||||
viewFocusGain();
|
||||
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowFocusRelinquish:
|
||||
keysCurrentlyDown.clear();
|
||||
viewFocusLoss();
|
||||
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowCollapsed:
|
||||
minimisedWindows.addIfNotAlreadyThere (windowRef);
|
||||
handleMovedOrResized();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowExpanded:
|
||||
minimisedWindows.removeValue (windowRef);
|
||||
handleMovedOrResized();
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowShown:
|
||||
break; // allow other handlers in the event chain to also get a look at the events
|
||||
|
||||
case kEventWindowClose:
|
||||
if (isSharedWindow)
|
||||
break; // break to let the OS delete the window
|
||||
|
||||
handleUserClosingWindow();
|
||||
return noErr; // avoids letting the OS to delete the window, we'll do that ourselves.
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return eventNotHandledErr;
|
||||
}
|
||||
|
|
@ -1579,6 +1603,21 @@ public:
|
|||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
static pascal OSStatus handleWindowEvent (EventHandlerCallRef callRef, EventRef theEvent, void* userData)
|
||||
{
|
||||
MessageManager::delayWaitCursor();
|
||||
|
||||
HIViewComponentPeer* const peer = (HIViewComponentPeer*) userData;
|
||||
|
||||
const MessageManagerLock messLock;
|
||||
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
return peer->handleWindowEventForPeer (callRef, theEvent);
|
||||
|
||||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static pascal OSStatus hiViewEventHandler (EventHandlerCallRef myHandler, EventRef theEvent, void* userData)
|
||||
{
|
||||
MessageManager::delayWaitCursor();
|
||||
|
|
@ -1674,14 +1713,22 @@ public:
|
|||
#endif
|
||||
Boolean accept = true;
|
||||
SetEventParameter (theEvent, kEventParamControlWouldAcceptDrop, typeBoolean, sizeof (accept), &accept);
|
||||
|
||||
peer->doDragDropEnter (theEvent);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
case kEventControlDragWithin:
|
||||
peer->doDragDropMove (theEvent);
|
||||
return noErr;
|
||||
|
||||
case kEventControlDragLeave:
|
||||
peer->doDragDropExit (theEvent);
|
||||
return noErr;
|
||||
|
||||
case kEventControlDragReceive:
|
||||
return peer->handleDragAndDrop (theEvent);
|
||||
peer->doDragDrop (theEvent);
|
||||
return noErr;
|
||||
|
||||
case kEventControlOwningWindowChanged:
|
||||
return peer->ownerWindowChanged (theEvent);
|
||||
|
|
@ -1718,6 +1765,7 @@ public:
|
|||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
WindowRef createNewWindow (const int windowStyleFlags)
|
||||
{
|
||||
jassert (windowRef == 0);
|
||||
|
|
@ -1894,6 +1942,7 @@ public:
|
|||
{ kEventClassControl, kEventControlSetFocusPart },
|
||||
{ kEventClassControl, kEventControlHitTest },
|
||||
{ kEventClassControl, kEventControlDragEnter },
|
||||
{ kEventClassControl, kEventControlDragLeave },
|
||||
{ kEventClassControl, kEventControlDragWithin },
|
||||
{ kEventClassControl, kEventControlDragReceive },
|
||||
{ kEventClassControl, kEventControlOwningWindowChanged }
|
||||
|
|
@ -1931,6 +1980,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool juce_isHIViewCreatedByJuce (HIViewRef view)
|
||||
{
|
||||
return juceHiViewClassNameCFString != 0
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/containers/juce_OwnedArray.h"
|
||||
#include "../../../src/juce_core/text/juce_LocalisedStrings.h"
|
||||
#include "../../../src/juce_appframework/application/juce_DeletedAtShutdown.h"
|
||||
|
||||
|
||||
static const String getDSErrorMessage (HRESULT hr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call
|
|||
else
|
||||
{
|
||||
// If a thread has a MessageManagerLock and then tries to call this method, it'll
|
||||
// deadlock because the message manager is blocked from running, and can't
|
||||
// deadlock because the message manager is blocked from running, and can't
|
||||
// call your function..
|
||||
jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager());
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
// these are in the windows SDK, but need to be repeated here for GCC..
|
||||
#ifndef GET_APPCOMMAND_LPARAM
|
||||
#define FAPPCOMMAND_MASK 0xF000
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((short) (HIWORD(lParam) & ~FAPPCOMMAND_MASK))
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((short) (HIWORD (lParam) & ~FAPPCOMMAND_MASK))
|
||||
#define APPCOMMAND_MEDIA_NEXTTRACK 11
|
||||
#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
|
||||
#define APPCOMMAND_MEDIA_STOP 13
|
||||
|
|
@ -520,8 +520,9 @@ public:
|
|||
fullScreen (false),
|
||||
isDragging (false),
|
||||
isMouseOver (false),
|
||||
currentWindowIcon (0),
|
||||
taskBarIcon (0),
|
||||
currentWindowIcon (0)
|
||||
dropTarget (0)
|
||||
{
|
||||
#if JUCE_ENABLE_WIN98_COMPATIBILITY
|
||||
juce_initialiseUnicodeWindowFunctions();
|
||||
|
|
@ -560,6 +561,12 @@ public:
|
|||
|
||||
if (currentWindowIcon != 0)
|
||||
DestroyIcon (currentWindowIcon);
|
||||
|
||||
if (dropTarget != 0)
|
||||
{
|
||||
dropTarget->Release();
|
||||
dropTarget = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -945,6 +952,7 @@ private:
|
|||
BorderSize windowBorder;
|
||||
HICON currentWindowIcon;
|
||||
NOTIFYICONDATA* taskBarIcon;
|
||||
IDropTarget* dropTarget;
|
||||
|
||||
//==============================================================================
|
||||
class TemporaryImage : public Timer
|
||||
|
|
@ -1153,7 +1161,10 @@ private:
|
|||
SetWindowLongPtr (hwnd, 8, (LONG_PTR) this);
|
||||
SetWindowLongPtr (hwnd, GWLP_USERDATA, improbableWindowNumber);
|
||||
|
||||
DragAcceptFiles (hwnd, TRUE);
|
||||
if (dropTarget == 0)
|
||||
dropTarget = new JuceDropTarget (this);
|
||||
|
||||
RegisterDragDrop (hwnd, dropTarget);
|
||||
|
||||
updateBorderSize();
|
||||
|
||||
|
|
@ -1169,6 +1180,7 @@ private:
|
|||
|
||||
static void* destroyWindowCallback (void* handle)
|
||||
{
|
||||
RevokeDragDrop ((HWND) handle);
|
||||
DestroyWindow ((HWND) handle);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1765,41 +1777,131 @@ private:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void doDroppedFiles (HDROP hdrop)
|
||||
class JuceDropTarget : public IDropTarget
|
||||
{
|
||||
POINT p;
|
||||
DragQueryPoint (hdrop, &p);
|
||||
|
||||
const int numFiles = DragQueryFile (hdrop, 0xffffffff, 0, 0);
|
||||
StringArray files;
|
||||
|
||||
const int size = sizeof (WCHAR) * MAX_PATH * 2 + 8;
|
||||
char* const name = (char*) juce_calloc (size);
|
||||
|
||||
for (int i = 0; i < numFiles; ++i)
|
||||
public:
|
||||
JuceDropTarget (Win32ComponentPeer* const owner_)
|
||||
: owner (owner_),
|
||||
refCount (1)
|
||||
{
|
||||
#if JUCE_ENABLE_WIN98_COMPATIBILITY
|
||||
if (wDragQueryFileW != 0)
|
||||
{
|
||||
wDragQueryFileW (hdrop, i, (LPWSTR) name, MAX_PATH);
|
||||
files.add ((LPWSTR) name);
|
||||
}
|
||||
else
|
||||
{
|
||||
DragQueryFile (hdrop, i, (LPSTR) name, MAX_PATH);
|
||||
files.add ((LPSTR) name);
|
||||
}
|
||||
#else
|
||||
DragQueryFileW (hdrop, i, (LPWSTR) name, MAX_PATH);
|
||||
files.add ((LPWSTR) name);
|
||||
#endif
|
||||
}
|
||||
|
||||
juce_free (name);
|
||||
DragFinish (hdrop);
|
||||
virtual ~JuceDropTarget()
|
||||
{
|
||||
jassert (refCount == 0);
|
||||
}
|
||||
|
||||
handleFilesDropped (p.x, p.y, files);
|
||||
}
|
||||
HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
|
||||
{
|
||||
if (id == IID_IUnknown || id == IID_IDropTarget)
|
||||
{
|
||||
AddRef();
|
||||
*result = this;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*result = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG __stdcall AddRef() { return ++refCount; }
|
||||
ULONG __stdcall Release() { jassert (refCount > 0); const int r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
HRESULT __stdcall DragEnter (IDataObject* pDataObject, DWORD /*grfKeyState*/, POINTL mousePos, DWORD* pdwEffect)
|
||||
{
|
||||
updateFileList (pDataObject);
|
||||
int x = mousePos.x, y = mousePos.y;
|
||||
owner->globalPositionToRelative (x, y);
|
||||
owner->handleFileDragMove (files, x, y);
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall DragLeave()
|
||||
{
|
||||
owner->handleFileDragExit (files);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall DragOver (DWORD /*grfKeyState*/, POINTL mousePos, DWORD* pdwEffect)
|
||||
{
|
||||
int x = mousePos.x, y = mousePos.y;
|
||||
owner->globalPositionToRelative (x, y);
|
||||
owner->handleFileDragMove (files, x, y);
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall Drop (IDataObject* pDataObject, DWORD /*grfKeyState*/, POINTL mousePos, DWORD* pdwEffect)
|
||||
{
|
||||
updateFileList (pDataObject);
|
||||
int x = mousePos.x, y = mousePos.y;
|
||||
owner->globalPositionToRelative (x, y);
|
||||
owner->handleFileDragDrop (files, x, y);
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Win32ComponentPeer* const owner;
|
||||
int refCount;
|
||||
StringArray files;
|
||||
|
||||
void updateFileList (IDataObject* const pDataObject)
|
||||
{
|
||||
files.clear();
|
||||
|
||||
FORMATETC format = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 };
|
||||
|
||||
if (pDataObject->GetData (&format, &medium) == S_OK)
|
||||
{
|
||||
const SIZE_T totalLen = GlobalSize (medium.hGlobal);
|
||||
const LPDROPFILES pDropFiles = (const LPDROPFILES) GlobalLock (medium.hGlobal);
|
||||
unsigned int i = 0;
|
||||
|
||||
if (pDropFiles->fWide)
|
||||
{
|
||||
const WCHAR* const fname = (WCHAR*) (((const char*) pDropFiles) + sizeof (DROPFILES));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
while (i + len < totalLen && fname [i + len] != 0)
|
||||
++len;
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
files.add (String (fname + i, len));
|
||||
i += len + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* const fname = ((const char*) pDropFiles) + sizeof (DROPFILES);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
while (i + len < totalLen && fname [i + len] != 0)
|
||||
++len;
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
files.add (String (fname + i, len));
|
||||
i += len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUnlock (medium.hGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
JuceDropTarget (const JuceDropTarget&);
|
||||
const JuceDropTarget& operator= (const JuceDropTarget&);
|
||||
};
|
||||
|
||||
void doSettingChange()
|
||||
{
|
||||
|
|
@ -2045,10 +2147,6 @@ private:
|
|||
return 0;
|
||||
|
||||
//==============================================================================
|
||||
case WM_DROPFILES:
|
||||
doDroppedFiles ((HDROP) wParam);
|
||||
break;
|
||||
|
||||
case WM_TRAYNOTIFY:
|
||||
if (component->isCurrentlyBlockedByAnotherModalComponent())
|
||||
{
|
||||
|
|
@ -2693,28 +2791,10 @@ public:
|
|||
|
||||
class JuceEnumFormatEtc : public IEnumFORMATETC
|
||||
{
|
||||
private:
|
||||
int refCount;
|
||||
FORMATETC* formats;
|
||||
int numFormats, index;
|
||||
|
||||
static void copyFormatEtc (FORMATETC& dest, FORMATETC& source)
|
||||
{
|
||||
dest = source;
|
||||
|
||||
if (source.ptd != 0)
|
||||
{
|
||||
dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
|
||||
*(dest.ptd) = *(source.ptd);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
JuceEnumFormatEtc (FORMATETC* const formats_,
|
||||
const int numFormats_)
|
||||
JuceEnumFormatEtc (const FORMATETC* const format_)
|
||||
: refCount (1),
|
||||
formats (formats_),
|
||||
numFormats (numFormats_),
|
||||
format (format_),
|
||||
index (0)
|
||||
{
|
||||
}
|
||||
|
|
@ -2745,7 +2825,7 @@ public:
|
|||
if (result == 0)
|
||||
return E_POINTER;
|
||||
|
||||
JuceEnumFormatEtc* const newOne = new JuceEnumFormatEtc (formats, numFormats);
|
||||
JuceEnumFormatEtc* const newOne = new JuceEnumFormatEtc (format);
|
||||
newOne->index = index;
|
||||
|
||||
*result = newOne;
|
||||
|
|
@ -2756,25 +2836,26 @@ public:
|
|||
{
|
||||
if (pceltFetched != 0)
|
||||
*pceltFetched = 0;
|
||||
|
||||
if (celt <= 0 || lpFormatEtc == 0 || index >= numFormats
|
||||
|| (pceltFetched == 0 && celt != 1))
|
||||
else if (celt != 1)
|
||||
return S_FALSE;
|
||||
|
||||
int numDone = 0;
|
||||
if (index == 0 && celt > 0 && lpFormatEtc != 0)
|
||||
{
|
||||
copyFormatEtc (lpFormatEtc [0], *format);
|
||||
++index;
|
||||
|
||||
while (index < numFormats && numDone < (int) celt)
|
||||
copyFormatEtc (lpFormatEtc [numDone++], formats [index++]);
|
||||
if (pceltFetched != 0)
|
||||
*pceltFetched = 1;
|
||||
|
||||
if (pceltFetched != 0)
|
||||
*pceltFetched = numDone;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return (numDone != 0) ? S_OK : S_FALSE;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT __stdcall Skip (ULONG celt)
|
||||
{
|
||||
if (index + (int) celt >= numFormats)
|
||||
if (index + (int) celt >= 1)
|
||||
return S_FALSE;
|
||||
|
||||
index += celt;
|
||||
|
|
@ -2786,42 +2867,45 @@ public:
|
|||
index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int refCount;
|
||||
const FORMATETC* const format;
|
||||
int index;
|
||||
|
||||
static void copyFormatEtc (FORMATETC& dest, const FORMATETC& source)
|
||||
{
|
||||
dest = source;
|
||||
|
||||
if (source.ptd != 0)
|
||||
{
|
||||
dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
|
||||
*(dest.ptd) = *(source.ptd);
|
||||
}
|
||||
}
|
||||
|
||||
JuceEnumFormatEtc (const JuceEnumFormatEtc&);
|
||||
const JuceEnumFormatEtc& operator= (const JuceEnumFormatEtc&);
|
||||
};
|
||||
|
||||
class JuceDataObject : public IDataObject
|
||||
{
|
||||
JuceDropSource* const dropSource;
|
||||
const FORMATETC* const format;
|
||||
const STGMEDIUM* const medium;
|
||||
int refCount;
|
||||
JuceDropSource* dropSource;
|
||||
|
||||
FORMATETC* formats;
|
||||
STGMEDIUM* mediums;
|
||||
int numFormats;
|
||||
|
||||
int indexOfFormat (const FORMATETC* const f) const
|
||||
{
|
||||
for (int i = 0; i < numFormats; ++i)
|
||||
{
|
||||
if (f->tymed == formats[i].tymed
|
||||
&& f->cfFormat == formats[i].cfFormat
|
||||
&& f->dwAspect == formats[i].dwAspect)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
JuceDataObject (const JuceDataObject&);
|
||||
const JuceDataObject& operator= (const JuceDataObject&);
|
||||
|
||||
public:
|
||||
JuceDataObject (JuceDropSource* const dropSource_,
|
||||
FORMATETC* const formats_,
|
||||
STGMEDIUM* const mediums_,
|
||||
const int numFormats_)
|
||||
: refCount (1),
|
||||
dropSource (dropSource_),
|
||||
formats (formats_),
|
||||
mediums (mediums_),
|
||||
numFormats (numFormats_)
|
||||
const FORMATETC* const format_,
|
||||
const STGMEDIUM* const medium_)
|
||||
: dropSource (dropSource_),
|
||||
format (format_),
|
||||
medium (medium_),
|
||||
refCount (1)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -2848,22 +2932,22 @@ public:
|
|||
|
||||
HRESULT __stdcall GetData (FORMATETC __RPC_FAR* pFormatEtc, STGMEDIUM __RPC_FAR* pMedium)
|
||||
{
|
||||
const int i = indexOfFormat (pFormatEtc);
|
||||
|
||||
if (i >= 0)
|
||||
if (pFormatEtc->tymed == format->tymed
|
||||
&& pFormatEtc->cfFormat == format->cfFormat
|
||||
&& pFormatEtc->dwAspect == format->dwAspect)
|
||||
{
|
||||
pMedium->tymed = formats[i].tymed;
|
||||
pMedium->tymed = format->tymed;
|
||||
pMedium->pUnkForRelease = 0;
|
||||
|
||||
if (formats[i].tymed == TYMED_HGLOBAL)
|
||||
if (format->tymed == TYMED_HGLOBAL)
|
||||
{
|
||||
const SIZE_T len = GlobalSize (mediums[i].hGlobal);
|
||||
void* const src = GlobalLock (mediums[i].hGlobal);
|
||||
const SIZE_T len = GlobalSize (medium->hGlobal);
|
||||
void* const src = GlobalLock (medium->hGlobal);
|
||||
void* const dst = GlobalAlloc (GMEM_FIXED, len);
|
||||
|
||||
memcpy (dst, src, len);
|
||||
|
||||
GlobalUnlock (mediums[i].hGlobal);
|
||||
GlobalUnlock (medium->hGlobal);
|
||||
|
||||
pMedium->hGlobal = dst;
|
||||
return S_OK;
|
||||
|
|
@ -2873,12 +2957,17 @@ public:
|
|||
return DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
HRESULT __stdcall QueryGetData (FORMATETC __RPC_FAR* result)
|
||||
HRESULT __stdcall QueryGetData (FORMATETC __RPC_FAR* f)
|
||||
{
|
||||
if (result == 0)
|
||||
if (f == 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return (indexOfFormat (result) >= 0) ? S_OK : DV_E_FORMATETC;
|
||||
if (f->tymed == format->tymed
|
||||
&& f->cfFormat == format->cfFormat
|
||||
&& f->dwAspect == format->dwAspect)
|
||||
return S_OK;
|
||||
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
HRESULT __stdcall GetCanonicalFormatEtc (FORMATETC __RPC_FAR*, FORMATETC __RPC_FAR* pFormatEtcOut)
|
||||
|
|
@ -2894,7 +2983,7 @@ public:
|
|||
|
||||
if (direction == DATADIR_GET)
|
||||
{
|
||||
*result = new JuceEnumFormatEtc (formats, numFormats);
|
||||
*result = new JuceEnumFormatEtc (format);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -2974,7 +3063,7 @@ static HDROP createHDrop (const StringArray& fileNames) throw()
|
|||
static bool performDragDrop (FORMATETC* const format, STGMEDIUM* const medium, const DWORD whatToDo) throw()
|
||||
{
|
||||
JuceDropSource* const source = new JuceDropSource();
|
||||
JuceDataObject* const data = new JuceDataObject (source, format, medium, 1);
|
||||
JuceDataObject* const data = new JuceDataObject (source, format, medium);
|
||||
|
||||
DWORD effect;
|
||||
const HRESULT res = DoDragDrop (data, source, whatToDo, &effect);
|
||||
|
|
@ -3043,11 +3132,11 @@ typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
|
|||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_ACCELERATION_ARB 0x2003
|
||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_RED_BITS_ARB 0x2015
|
||||
#define WGL_GREEN_BITS_ARB 0x2017
|
||||
#define WGL_BLUE_BITS_ARB 0x2019
|
||||
|
|
@ -3079,7 +3168,7 @@ static void getWglExtensions (HDC dc, StringArray& result) throw()
|
|||
class WindowedGLContext : public OpenGLContext
|
||||
{
|
||||
public:
|
||||
WindowedGLContext (Component* const component_,
|
||||
WindowedGLContext (Component* const component_,
|
||||
HGLRC contextToShareWith,
|
||||
const OpenGLPixelFormat& pixelFormat)
|
||||
: renderContext (0),
|
||||
|
|
@ -3323,7 +3412,7 @@ public:
|
|||
|
||||
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = 0;
|
||||
|
||||
if (availableExtensions.contains ("WGL_EXT_swap_control")
|
||||
if (availableExtensions.contains ("WGL_EXT_swap_control")
|
||||
&& WGL_EXT_FUNCTION_INIT (PFNWGLGETSWAPINTERVALEXTPROC, wglGetSwapIntervalEXT))
|
||||
return wglGetSwapIntervalEXT();
|
||||
|
||||
|
|
|
|||
|
|
@ -3893,6 +3893,10 @@
|
|||
RelativePath="..\..\..\src\juce_appframework\gui\components\mouse\juce_DragAndDropTarget.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\gui\components\mouse\juce_FileDragAndDropTarget.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\gui\components\mouse\juce_LassoComponent.h"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Changelist for version 1.45
|
|||
- audio plugins: new methods AudioProcessor::beginParameterChangeGesture() and endParameterChangeGesture() let you tell the host when a parameter-change action starts and finishes.
|
||||
- audio plugins: new method AudioProcessor::updateHostDisplay() to tell the host that something about your plugin has changed and that it should refresh its display.
|
||||
- new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath.
|
||||
- new class: FileDragAndDropTarget, which replaces the old method Component::filesDropped. To use it, just make your component inherit from FileDragAndDropTarget, and it'll receive external file drops. This provides more functionality than the old method, allowing you to track the drag enter/exit/movements as well as just reacting to the drop itself.
|
||||
- added a critical section option to ReferenceCountedArray
|
||||
- refactored and added features to the Socket class, replacing it with StreamableSocket (basically the same as the original class), and DatagramSocket.
|
||||
- refactored the OpenGLComponent, adding new classes OpenGLPixelFormat and OpenGLContext
|
||||
|
|
|
|||
|
|
@ -463,26 +463,47 @@ void MainHostWindow::showAudioSettings()
|
|||
graphEditor->graph.removeIllegalConnections();
|
||||
}
|
||||
|
||||
bool MainHostWindow::filesDropped (const StringArray& files, int x, int y)
|
||||
bool MainHostWindow::isInterestedInFileDrag (const StringArray&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainHostWindow::fileDragEnter (const StringArray&, int, int)
|
||||
{
|
||||
}
|
||||
|
||||
void MainHostWindow::fileDragMove (const StringArray&, int, int)
|
||||
{
|
||||
}
|
||||
|
||||
void MainHostWindow::fileDragExit (const StringArray&)
|
||||
{
|
||||
}
|
||||
|
||||
void MainHostWindow::filesDropped (const StringArray& files, int x, int y)
|
||||
{
|
||||
if (files.size() == 1 && File (files[0]).hasFileExtension (filenameSuffix))
|
||||
{
|
||||
GraphDocumentComponent* const graphEditor = getGraphEditor();
|
||||
|
||||
if (graphEditor == 0)
|
||||
return false;
|
||||
|
||||
return graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk
|
||||
&& graphEditor->graph.loadFrom (File (files[0]), true);
|
||||
if (graphEditor != 0
|
||||
&& graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk)
|
||||
{
|
||||
graphEditor->graph.loadFrom (File (files[0]), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OwnedArray <PluginDescription> typesFound;
|
||||
knownPluginList.scanAndAddDragAndDroppedFiles (files, typesFound);
|
||||
|
||||
OwnedArray <PluginDescription> typesFound;
|
||||
knownPluginList.scanAndAddDragAndDroppedFiles (files, typesFound);
|
||||
GraphDocumentComponent* const graphEditor = getGraphEditor();
|
||||
if (graphEditor != 0)
|
||||
relativePositionToOtherComponent (graphEditor, x, y);
|
||||
|
||||
for (int i = 0; i < jmin (5, typesFound.size()); ++i)
|
||||
createPlugin (typesFound.getUnchecked(i), x, y);
|
||||
|
||||
return typesFound.size() > 0;
|
||||
for (int i = 0; i < jmin (5, typesFound.size()); ++i)
|
||||
createPlugin (typesFound.getUnchecked(i), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
GraphDocumentComponent* MainHostWindow::getGraphEditor() const
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ extern ApplicationCommandManager* commandManager;
|
|||
class MainHostWindow : public DocumentWindow,
|
||||
public MenuBarModel,
|
||||
public ApplicationCommandTarget,
|
||||
public ChangeListener
|
||||
public ChangeListener,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -67,7 +68,12 @@ public:
|
|||
//==============================================================================
|
||||
void closeButtonPressed();
|
||||
void changeListenerCallback (void*);
|
||||
bool filesDropped (const StringArray& filenames, int x, int y);
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
void fileDragEnter (const StringArray& files, int, int);
|
||||
void fileDragMove (const StringArray& files, int, int);
|
||||
void fileDragExit (const StringArray& files);
|
||||
void filesDropped (const StringArray& files, int, int);
|
||||
|
||||
const StringArray getMenuBarNames();
|
||||
const PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName);
|
||||
|
|
|
|||
|
|
@ -120,14 +120,12 @@ bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile,
|
|||
{
|
||||
const PluginDescription* const d = types.getUnchecked(i);
|
||||
|
||||
if (d->file == possiblePluginFile
|
||||
&& d->lastFileModTime != possiblePluginFile.getLastModificationTime())
|
||||
if (d->file == possiblePluginFile)
|
||||
{
|
||||
needsRescanning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
typesFound.add (new PluginDescription (*d));
|
||||
if (d->lastFileModTime != possiblePluginFile.getLastModificationTime())
|
||||
needsRescanning = true;
|
||||
else
|
||||
typesFound.add (new PluginDescription (*d));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,12 +201,15 @@ void PluginListComponent::buttonClicked (Button* b)
|
|||
}
|
||||
}
|
||||
|
||||
bool PluginListComponent::filesDropped (const StringArray& files, int, int)
|
||||
bool PluginListComponent::isInterestedInFileDrag (const StringArray& files)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginListComponent::filesDropped (const StringArray& files, int, int)
|
||||
{
|
||||
OwnedArray <PluginDescription> typesFound;
|
||||
list.scanAndAddDragAndDroppedFiles (files, typesFound);
|
||||
|
||||
return typesFound.size() > 0;
|
||||
}
|
||||
|
||||
void PluginListComponent::scanFor (AudioPluginFormat* format)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,9 @@ public:
|
|||
/** @internal */
|
||||
void resized();
|
||||
/** @internal */
|
||||
bool filesDropped (const StringArray& files, int x, int y);
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
/** @internal */
|
||||
void filesDropped (const StringArray& files, int, int);
|
||||
/** @internal */
|
||||
int getNumRows();
|
||||
/** @internal */
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
#include "../../../../../juce.h"
|
||||
#include "juce_VSTPluginInstance.h"
|
||||
|
||||
#if JUCE_LINUX
|
||||
#if JUCE_LINUX
|
||||
#define Font JUCE_NAMESPACE::Font
|
||||
#define KeyPress JUCE_NAMESPACE::KeyPress
|
||||
#define Drawable JUCE_NAMESPACE::Drawable
|
||||
|
|
@ -225,7 +225,7 @@ static int getPropertyFromXWindow (Window handle, Atom atom)
|
|||
|
||||
XSetErrorHandler (oldErrorHandler);
|
||||
|
||||
return (userCount == 1 && ! xErrorTriggered) ? *(int*) data
|
||||
return (userCount == 1 && ! xErrorTriggered) ? *(int*) data
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1452,7 +1452,7 @@ private:
|
|||
h = 150;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pluginWindow != 0)
|
||||
XMapRaised (display, pluginWindow);
|
||||
#endif
|
||||
|
|
@ -1611,7 +1611,7 @@ private:
|
|||
}
|
||||
else if (pluginWindow != 0)
|
||||
{
|
||||
// if the plugin has a window, then send the event to the window so that
|
||||
// if the plugin has a window, then send the event to the window so that
|
||||
// its message thread will pick it up..
|
||||
XSendEvent (display, pluginWindow, False, 0L, event);
|
||||
XFlush (display);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
//==============================================================================
|
||||
/**
|
||||
This function must be implemented to create a new instance of your
|
||||
This function must be implemented to create a new instance of your
|
||||
plugin object.
|
||||
*/
|
||||
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||
|
|
|
|||
|
|
@ -7961,4 +7961,3 @@ static const unsigned char temp17[] = {47,42,13,10,32,32,61,61,61,61,61,61,61,61
|
|||
110,100,77,97,110,97,103,101,114,42,32,99,111,109,109,97,110,100,77,97,110,97,103,101,114,41,13,10,123,13,10,32,32,32,32,114,101,116,117,114,
|
||||
110,32,110,101,119,32,87,105,100,103,101,116,115,68,101,109,111,32,40,99,111,109,109,97,110,100,77,97,110,97,103,101,114,41,59,13,10,125,13,10,0,0};
|
||||
const char* BinaryData::widgetsdemo_cpp = (const char*) temp17;
|
||||
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ public:
|
|||
AudioDeviceSelectorComponent audioSettingsComp (audioDeviceManager,
|
||||
0, 1,
|
||||
2, 2,
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
|
||||
// ...and show it in a DialogWindow...
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ public:
|
|||
AudioDeviceSelectorComponent audioSettingsComp (audioDeviceManager,
|
||||
0, 1,
|
||||
2, 2,
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
|
||||
// ...and show it in a DialogWindow...
|
||||
|
|
|
|||
|
|
@ -911,4 +911,3 @@ static const unsigned char temp4[] = {137,80,78,71,13,10,26,10,0,0,0,13,73,72,68
|
|||
0,98,28,9,155,95,0,2,104,68,236,11,1,8,160,17,225,73,128,0,3,0,120,52,172,151,198,78,252,63,0,0,0,0,73,69,78,68,174,66,
|
||||
96,130,0,0};
|
||||
const char* BinaryData::prefs_misc_png = (const char*) temp4;
|
||||
|
||||
|
|
|
|||
|
|
@ -357,9 +357,15 @@ bool ComponentLayoutEditor::keyPressed (const KeyPress& key)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
bool ComponentLayoutEditor::isInterestedInFileDrag (const StringArray& filenames)
|
||||
{
|
||||
File f (filenames [0]);
|
||||
const File f (filenames [0]);
|
||||
return f.hasFileExtension (T(".cpp"));
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
{
|
||||
const File f (filenames [0]);
|
||||
|
||||
if (f.hasFileExtension (T(".cpp")))
|
||||
{
|
||||
|
|
@ -385,12 +391,8 @@ bool ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, i
|
|||
}
|
||||
|
||||
layout.getDocument()->getUndoManager().beginNewTransaction();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ComponentOverlayComponent* ComponentLayoutEditor::getOverlayCompFor (Component* compToFind) const
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
*/
|
||||
class ComponentLayoutEditor : public Component,
|
||||
public ChangeListener,
|
||||
public FileDragAndDropTarget,
|
||||
public LassoSource <Component*>
|
||||
{
|
||||
public:
|
||||
|
|
@ -59,7 +60,9 @@ public:
|
|||
void mouseDrag (const MouseEvent& e);
|
||||
void mouseUp (const MouseEvent& e);
|
||||
bool keyPressed (const KeyPress& key);
|
||||
bool filesDropped (const StringArray& filenames, int x, int y);
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
void filesDropped (const StringArray& filenames, int x, int y);
|
||||
|
||||
ComponentLayout& getLayout() const throw() { return layout; }
|
||||
|
||||
|
|
|
|||
|
|
@ -201,20 +201,30 @@ bool MainWindow::openFile (const File& file)
|
|||
return newDoc != 0;
|
||||
}
|
||||
|
||||
bool MainWindow::filesDropped (const StringArray& filenames, int mouseX, int mouseY)
|
||||
bool MainWindow::isInterestedInFileDrag (const StringArray& filenames)
|
||||
{
|
||||
for (int i = filenames.size(); --i >= 0;)
|
||||
{
|
||||
const File f (filenames[i]);
|
||||
|
||||
if (f.hasFileExtension (T(".cpp")))
|
||||
if (openFile (f))
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::filesDropped (const StringArray& filenames, int mouseX, int mouseY)
|
||||
{
|
||||
for (int i = filenames.size(); --i >= 0;)
|
||||
{
|
||||
const File f (filenames[i]);
|
||||
|
||||
if (f.hasFileExtension (T(".cpp")) && openFile (f))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::activeWindowStatusChanged()
|
||||
{
|
||||
DocumentWindow::activeWindowStatusChanged();
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ class MultiDocHolder;
|
|||
*/
|
||||
class MainWindow : public DocumentWindow,
|
||||
public MenuBarModel,
|
||||
public ApplicationCommandTarget
|
||||
public ApplicationCommandTarget,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -59,7 +60,9 @@ public:
|
|||
bool closeDocument (JucerDocumentHolder* designHolder);
|
||||
bool closeAllDocuments();
|
||||
|
||||
bool filesDropped (const StringArray& filenames, int mouseX, int mouseY);
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
void filesDropped (const StringArray& filenames, int mouseX, int mouseY);
|
||||
|
||||
void activeWindowStatusChanged();
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -286,9 +286,20 @@ SelectedItemSet <PaintElement*>& PaintRoutineEditor::getLassoSelection()
|
|||
return graphics.getSelectedElements();
|
||||
}
|
||||
|
||||
bool PaintRoutineEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
bool PaintRoutineEditor::isInterestedInFileDrag (const StringArray& files)
|
||||
{
|
||||
File f (filenames [0]);
|
||||
const File f (files [0]);
|
||||
|
||||
return f.hasFileExtension ("jpg")
|
||||
|| f.hasFileExtension ("jpeg")
|
||||
|| f.hasFileExtension ("png")
|
||||
|| f.hasFileExtension ("gif")
|
||||
|| f.hasFileExtension ("svg");
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
{
|
||||
const File f (filenames [0]);
|
||||
|
||||
if (f.existsAsFile())
|
||||
{
|
||||
|
|
@ -305,10 +316,6 @@ bool PaintRoutineEditor::filesDropped (const StringArray& filenames, int x, int
|
|||
jlimit (10, getHeight() - 10, y));
|
||||
|
||||
document.getUndoManager().beginNewTransaction();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ class JucerDocumentHolder;
|
|||
*/
|
||||
class PaintRoutineEditor : public Component,
|
||||
public ChangeListener,
|
||||
public LassoSource <PaintElement*>
|
||||
public LassoSource <PaintElement*>,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -68,7 +69,8 @@ public:
|
|||
|
||||
SelectedItemSet <PaintElement*>& getLassoSelection();
|
||||
|
||||
bool filesDropped (const StringArray& filenames, int x, int y);
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
void filesDropped (const StringArray& filenames, int x, int y);
|
||||
|
||||
const Rectangle getComponentArea() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -431,6 +431,9 @@
|
|||
#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__
|
||||
#include "juce_appframework/gui/components/mouse/juce_DragAndDropTarget.h"
|
||||
#endif
|
||||
#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__
|
||||
#include "juce_appframework/gui/components/mouse/juce_FileDragAndDropTarget.h"
|
||||
#endif
|
||||
#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__
|
||||
#include "juce_appframework/gui/components/mouse/juce_LassoComponent.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ public:
|
|||
The specified device will be opened automatically and can be retrieved with the
|
||||
getDefaultMidiOutput() method.
|
||||
|
||||
Pass in an empty string to deselect all devices. For the default device, you
|
||||
Pass in an empty string to deselect all devices. For the default device, you
|
||||
can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()].
|
||||
|
||||
@see getDefaultMidiOutput, getDefaultMidiOutputName
|
||||
|
|
@ -324,7 +324,7 @@ public:
|
|||
|
||||
/** Returns the current default midi output device.
|
||||
|
||||
If no device has been selected, or the device can't be opened, this will
|
||||
If no device has been selected, or the device can't be opened, this will
|
||||
return 0.
|
||||
|
||||
@see getDefaultMidiOutputName
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ AudioProcessor::~AudioProcessor()
|
|||
// that it refers to is deleted..
|
||||
jassert (activeEditor == 0);
|
||||
|
||||
#ifdef JUCE_DEBUG
|
||||
#ifdef JUCE_DEBUG
|
||||
// This will fail if you've called beginParameterChangeGesture() for one
|
||||
// or more parameters without having made a corresponding call to endParameterChangeGesture...
|
||||
jassert (changingParams.countNumberOfSetBits() == 0);
|
||||
|
|
@ -127,7 +127,7 @@ void AudioProcessor::beginParameterChangeGesture (int parameterIndex)
|
|||
{
|
||||
jassert (parameterIndex >= 0 && parameterIndex < getNumParameters());
|
||||
|
||||
#ifdef JUCE_DEBUG
|
||||
#ifdef JUCE_DEBUG
|
||||
// This means you've called beginParameterChangeGesture twice in succession without a matching
|
||||
// call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
|
||||
jassert (! changingParams [parameterIndex]);
|
||||
|
|
@ -148,7 +148,7 @@ void AudioProcessor::endParameterChangeGesture (int parameterIndex)
|
|||
{
|
||||
jassert (parameterIndex >= 0 && parameterIndex < getNumParameters());
|
||||
|
||||
#ifdef JUCE_DEBUG
|
||||
#ifdef JUCE_DEBUG
|
||||
// This means you've called endParameterChangeGesture without having previously called
|
||||
// endParameterChangeGesture. That might be fine in most hosts, but better to keep the
|
||||
// calls matched correctly.
|
||||
|
|
|
|||
|
|
@ -1089,7 +1089,7 @@ void Slider::restoreMouseIfHidden()
|
|||
c->enableUnboundedMouseMovement (false);
|
||||
|
||||
const double pos = (sliderBeingDragged == 2) ? getMaxValue()
|
||||
: ((sliderBeingDragged == 1) ? getMinValue()
|
||||
: ((sliderBeingDragged == 1) ? getMinValue()
|
||||
: currentValue);
|
||||
|
||||
const int pixelPos = (int) getLinearSliderPos (pos);
|
||||
|
|
|
|||
|
|
@ -202,10 +202,13 @@ void FileSearchPathListComponent::resized()
|
|||
changeButton->setTopRightPosition (upButton->getX() - 8, buttonY);
|
||||
}
|
||||
|
||||
bool FileSearchPathListComponent::filesDropped (const StringArray& filenames, int /*mouseX*/, int mouseY)
|
||||
bool FileSearchPathListComponent::isInterestedInFileDrag (const StringArray&)
|
||||
{
|
||||
bool usedAny = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileSearchPathListComponent::filesDropped (const StringArray& filenames, int, int mouseY)
|
||||
{
|
||||
for (int i = filenames.size(); --i >= 0;)
|
||||
{
|
||||
const File f (filenames[i]);
|
||||
|
|
@ -215,11 +218,8 @@ bool FileSearchPathListComponent::filesDropped (const StringArray& filenames, in
|
|||
const int row = listBox->getRowContainingPosition (0, mouseY - listBox->getY());
|
||||
path.add (f, row);
|
||||
changed();
|
||||
usedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
return usedAny;
|
||||
}
|
||||
|
||||
void FileSearchPathListComponent::buttonClicked (Button* button)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "../controls/juce_ListBox.h"
|
||||
#include "../buttons/juce_Button.h"
|
||||
#include "../mouse/juce_FileDragAndDropTarget.h"
|
||||
#include "../../../../juce_core/io/files/juce_FileSearchPath.h"
|
||||
|
||||
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
*/
|
||||
class JUCE_API FileSearchPathListComponent : public Component,
|
||||
public SettableTooltipClient,
|
||||
public FileDragAndDropTarget,
|
||||
private ButtonListener,
|
||||
private ListBoxModel
|
||||
{
|
||||
|
|
@ -103,7 +105,9 @@ public:
|
|||
/** @internal */
|
||||
void paint (Graphics& g);
|
||||
/** @internal */
|
||||
bool filesDropped (const StringArray& filenames, int mouseX, int mouseY);
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
/** @internal */
|
||||
void filesDropped (const StringArray& files, int, int);
|
||||
/** @internal */
|
||||
void buttonClicked (Button* button);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ FilenameComponent::FilenameComponent (const String& name,
|
|||
maxRecentFiles (30),
|
||||
isDir (isDirectory),
|
||||
isSaving (isForSaving),
|
||||
isFileDragOver (false),
|
||||
wildcard (fileBrowserWildcard),
|
||||
enforcedSuffix (enforcedSuffix_)
|
||||
{
|
||||
|
|
@ -73,6 +74,15 @@ FilenameComponent::~FilenameComponent()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void FilenameComponent::paintOverChildren (Graphics& g)
|
||||
{
|
||||
if (isFileDragOver)
|
||||
{
|
||||
g.setColour (Colours::red.withAlpha (0.2f));
|
||||
g.drawRect (0, 0, getWidth(), getHeight(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
void FilenameComponent::resized()
|
||||
{
|
||||
getLookAndFeel().layoutFilenameComponent (*this, filenameBox, browseButton);
|
||||
|
|
@ -126,14 +136,32 @@ void FilenameComponent::comboBoxChanged (ComboBox*)
|
|||
setCurrentFile (getCurrentFile(), true);
|
||||
}
|
||||
|
||||
bool FilenameComponent::filesDropped (const StringArray& filenames, int, int)
|
||||
bool FilenameComponent::isInterestedInFileDrag (const StringArray&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilenameComponent::filesDropped (const StringArray& filenames, int, int)
|
||||
{
|
||||
isFileDragOver = false;
|
||||
repaint();
|
||||
|
||||
const File f (filenames[0]);
|
||||
|
||||
if (f.exists() && (f.isDirectory() == isDir))
|
||||
setCurrentFile (f, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
void FilenameComponent::fileDragEnter (const StringArray&, int, int)
|
||||
{
|
||||
isFileDragOver = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void FilenameComponent::fileDragExit (const StringArray&)
|
||||
{
|
||||
isFileDragOver = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "../../../events/juce_AsyncUpdater.h"
|
||||
#include "../buttons/juce_TextButton.h"
|
||||
#include "../../../../juce_core/io/files/juce_File.h"
|
||||
#include "../mouse/juce_FileDragAndDropTarget.h"
|
||||
class FilenameComponent;
|
||||
|
||||
|
||||
|
|
@ -75,6 +76,7 @@ public:
|
|||
*/
|
||||
class JUCE_API FilenameComponent : public Component,
|
||||
public SettableTooltipClient,
|
||||
public FileDragAndDropTarget,
|
||||
private AsyncUpdater,
|
||||
private ButtonListener,
|
||||
private ComboBoxListener
|
||||
|
|
@ -188,11 +190,19 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paintOverChildren (Graphics& g);
|
||||
/** @internal */
|
||||
void resized();
|
||||
/** @internal */
|
||||
void lookAndFeelChanged();
|
||||
/** @internal */
|
||||
bool filesDropped (const StringArray& filenames, int mouseX, int mouseY);
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
/** @internal */
|
||||
void filesDropped (const StringArray& files, int, int);
|
||||
/** @internal */
|
||||
void fileDragEnter (const StringArray& files, int, int);
|
||||
/** @internal */
|
||||
void fileDragExit (const StringArray& files);
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
|
@ -203,7 +213,7 @@ private:
|
|||
String lastFilename;
|
||||
Button* browseButton;
|
||||
int maxRecentFiles;
|
||||
bool isDir, isSaving;
|
||||
bool isDir, isSaving, isFileDragOver;
|
||||
String wildcard, enforcedSuffix, browseButtonText;
|
||||
SortedSet <void*> listeners;
|
||||
File defaultBrowseFile;
|
||||
|
|
|
|||
|
|
@ -3502,38 +3502,6 @@ void Component::internalModifierKeysChanged()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
bool Component::filesDropped (const StringArray&, int, int)
|
||||
{
|
||||
// base class returns false to let the message get passed up to its parent
|
||||
return false;
|
||||
}
|
||||
|
||||
void Component::internalFilesDropped (const int x,
|
||||
const int y,
|
||||
const StringArray& files)
|
||||
{
|
||||
if (isCurrentlyBlockedByAnotherModalComponent())
|
||||
{
|
||||
internalModalInputAttempt();
|
||||
|
||||
if (isCurrentlyBlockedByAnotherModalComponent())
|
||||
return;
|
||||
}
|
||||
|
||||
Component* c = getComponentAt (x, y);
|
||||
|
||||
while (c->isValidComponent())
|
||||
{
|
||||
int rx = x, ry = y;
|
||||
relativePositionToOtherComponent (c, rx, ry);
|
||||
|
||||
if (c->filesDropped (files, rx, ry))
|
||||
break;
|
||||
|
||||
c = c->getParentComponent();
|
||||
}
|
||||
}
|
||||
|
||||
ComponentPeer* Component::getPeer() const throw()
|
||||
{
|
||||
if (flags.hasHeavyweightPeerFlag)
|
||||
|
|
|
|||
|
|
@ -1688,22 +1688,6 @@ public:
|
|||
*/
|
||||
void removeComponentListener (ComponentListener* const listenerToRemove) throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Called when files are dragged-and-dropped onto this component.
|
||||
|
||||
If the component isn't interested in the files, it should return false, to indicate
|
||||
that its parent can be offered the files instead.
|
||||
|
||||
@param filenames a list of the filenames of the files that were dropped
|
||||
@param mouseX x co-ordinate of the mouse when they were dropped, (relative to this
|
||||
component's top-left)
|
||||
@param mouseY y co-ordinate of the mouse when they were dropped, (relative to this
|
||||
component's top-left)
|
||||
*/
|
||||
virtual bool filesDropped (const StringArray& filenames,
|
||||
int mouseX,
|
||||
int mouseY);
|
||||
|
||||
//==============================================================================
|
||||
/** Dispatches a numbered message to this component.
|
||||
|
||||
|
|
@ -2078,7 +2062,6 @@ private:
|
|||
void internalModifierKeysChanged();
|
||||
void internalChildrenChanged();
|
||||
void internalHierarchyChanged();
|
||||
void internalFilesDropped (const int x, const int y, const StringArray& files);
|
||||
void internalUpdateMouseCursor (const bool forcedUpdate) throw();
|
||||
void sendMovedResizedMessages (const bool wasMoved, const bool wasResized);
|
||||
void repaintParent() throw();
|
||||
|
|
@ -2099,6 +2082,13 @@ private:
|
|||
const Rectangle getUnclippedArea() const;
|
||||
void sendVisibilityChangeMessage();
|
||||
|
||||
//==============================================================================
|
||||
// This is included here just to cause a compile error if your code is still handling
|
||||
// drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget
|
||||
// class, which is easy (just make your class inherit from FileDragAndDropTarget, and
|
||||
// implement its methods instead of this Component method).
|
||||
virtual void filesDropped (const StringArray&, int, int) {}
|
||||
|
||||
// components aren't allowed to have copy constructors, as this would mess up parent
|
||||
// hierarchies. You might need to give your subclasses a private dummy constructor like
|
||||
// this one to avoid compiler warnings.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../../events/juce_Timer.h"
|
||||
#include "../../../../juce_core/basics/juce_Random.h"
|
||||
#include "../../graphics/imaging/juce_Image.h"
|
||||
#include "juce_FileDragAndDropTarget.h"
|
||||
|
||||
bool juce_performDragDropFiles (const StringArray& files, const bool copyFiles, bool& shouldStop);
|
||||
bool juce_performDragDropText (const String& text, bool& shouldStop);
|
||||
|
|
@ -477,4 +478,19 @@ bool DragAndDropTarget::shouldDrawDragImageWhenOver()
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void FileDragAndDropTarget::fileDragEnter (const StringArray&, int, int)
|
||||
{
|
||||
}
|
||||
|
||||
void FileDragAndDropTarget::fileDragMove (const StringArray&, int, int)
|
||||
{
|
||||
}
|
||||
|
||||
void FileDragAndDropTarget::fileDragExit (const StringArray&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@
|
|||
DragAndDropContainer component.
|
||||
|
||||
Note: If all that you need to do is to respond to files being drag-and-dropped from
|
||||
the operating system onto your component, you don't need any of these classes: you can do this
|
||||
simply by overriding Component::filesDropped().
|
||||
the operating system onto your component, you don't need any of these classes: instead
|
||||
see the FileDragAndDropTarget class.
|
||||
|
||||
@see DragAndDropContainer
|
||||
@see DragAndDropContainer, FileDragAndDropTarget
|
||||
*/
|
||||
class JUCE_API DragAndDropTarget
|
||||
{
|
||||
|
|
@ -119,6 +119,9 @@ public:
|
|||
When the user drops an item this get called, and you can use the description to
|
||||
work out whether your object wants to deal with it or not.
|
||||
|
||||
Note that after this is called, the itemDragExit method may not be called, so you should
|
||||
clean up in here if there's anything you need to do when the drag finishes.
|
||||
|
||||
@param sourceDescription the description string passed into DragAndDropContainer::startDragging()
|
||||
@param sourceComponent the component passed into DragAndDropContainer::startDragging()
|
||||
@param x the mouse x position, relative to this component
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public:
|
|||
|
||||
/** Sets whether the context checks the vertical sync before swapping.
|
||||
|
||||
The value is the number of frames to allow between buffer-swapping. This is
|
||||
The value is the number of frames to allow between buffer-swapping. This is
|
||||
fairly system-dependent, but 0 turns off syncing, 1 makes it swap on frame-boundaries,
|
||||
and greater numbers indicate that it should swap less often.
|
||||
|
||||
|
|
@ -235,10 +235,10 @@ public:
|
|||
that your context needs.
|
||||
|
||||
New contexts are created on-demand by the makeCurrentContextActive() method - so
|
||||
if the context is deleted, e.g. by changing the pixel format or window, no context
|
||||
if the context is deleted, e.g. by changing the pixel format or window, no context
|
||||
will be created until the next call to makeCurrentContextActive(), which will
|
||||
synchronously create one and call this method. This means that if you're using
|
||||
a non-GUI thread for rendering, you can make sure this method is be called by
|
||||
a non-GUI thread for rendering, you can make sure this method is be called by
|
||||
your renderer thread.
|
||||
|
||||
When this callback happens, the context will already have been made current
|
||||
|
|
@ -252,7 +252,7 @@ public:
|
|||
/** Returns the context that will draw into this component.
|
||||
|
||||
This may return 0 if the component is currently invisible or hasn't currently
|
||||
got a context. The context object can be deleted and a new one created during
|
||||
got a context. The context object can be deleted and a new one created during
|
||||
the lifetime of this component, and there may be times when it doesn't have one.
|
||||
|
||||
@see newOpenGLContextCreated()
|
||||
|
|
@ -267,8 +267,8 @@ public:
|
|||
If this returns false, then the context isn't active, so you should avoid
|
||||
making any calls.
|
||||
|
||||
This call may actually create a context if one isn't currently initialised. If
|
||||
it does this, it will also synchronously call the newOpenGLContextCreated()
|
||||
This call may actually create a context if one isn't currently initialised. If
|
||||
it does this, it will also synchronously call the newOpenGLContextCreated()
|
||||
method to let you initialise it as necessary.
|
||||
|
||||
@see OpenGLContext::makeActive
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ struct AlertWindowInfo
|
|||
|
||||
int run() const
|
||||
{
|
||||
return (int) (pointer_sized_int)
|
||||
return (int) (pointer_sized_int)
|
||||
MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../../../juce_core/basics/juce_Time.h"
|
||||
#include "../../../../juce_core/basics/juce_Random.h"
|
||||
#include "../layout/juce_ComponentBoundsConstrainer.h"
|
||||
|
||||
#include "../mouse/juce_FileDragAndDropTarget.h"
|
||||
|
||||
//#define JUCE_ENABLE_REPAINT_DEBUGGING 1
|
||||
|
||||
|
|
@ -70,6 +70,8 @@ ComponentPeer::ComponentPeer (Component* const component_,
|
|||
lastPaintTime (0),
|
||||
constrainer (0),
|
||||
lastFocusedComponent (0),
|
||||
dragAndDropTargetComponent (0),
|
||||
lastDragAndDropCompUnderMouse (0),
|
||||
fakeMouseMessageSent (false),
|
||||
isWindowMinimised (false)
|
||||
{
|
||||
|
|
@ -79,6 +81,7 @@ ComponentPeer::ComponentPeer (Component* const component_,
|
|||
ComponentPeer::~ComponentPeer()
|
||||
{
|
||||
heavyweightPeers.removeValue (this);
|
||||
delete dragAndDropTargetComponent;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -451,7 +454,7 @@ bool ComponentPeer::handleKeyPress (const int keyCode,
|
|||
|
||||
if (keyWasUsed || deletionChecker.hasBeenDeleted())
|
||||
break;
|
||||
|
||||
|
||||
if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0)
|
||||
{
|
||||
Component::getCurrentlyFocusedComponent()
|
||||
|
|
@ -654,13 +657,111 @@ const Rectangle& ComponentPeer::getNonFullScreenBounds() const throw()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void ComponentPeer::handleFilesDropped (int x, int y, const StringArray& files)
|
||||
static FileDragAndDropTarget* findDragAndDropTarget (Component* c,
|
||||
const StringArray& files,
|
||||
FileDragAndDropTarget* const lastOne)
|
||||
{
|
||||
while (c != 0)
|
||||
{
|
||||
FileDragAndDropTarget* const t = dynamic_cast <FileDragAndDropTarget*> (c);
|
||||
|
||||
if (t != 0 && (t == lastOne || t->isInterestedInFileDrag (files)))
|
||||
return t;
|
||||
|
||||
c = c->getParentComponent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ComponentPeer::handleFileDragMove (const StringArray& files, int x, int y)
|
||||
{
|
||||
updateCurrentModifiers();
|
||||
|
||||
component->internalFilesDropped (x, y, files);
|
||||
FileDragAndDropTarget* lastTarget = 0;
|
||||
|
||||
if (dragAndDropTargetComponent != 0 && ! dragAndDropTargetComponent->hasBeenDeleted())
|
||||
lastTarget = const_cast <FileDragAndDropTarget*> (dynamic_cast <const FileDragAndDropTarget*> (dragAndDropTargetComponent->getComponent()));
|
||||
|
||||
FileDragAndDropTarget* newTarget = 0;
|
||||
|
||||
Component* const compUnderMouse = component->getComponentAt (x, y);
|
||||
|
||||
if (compUnderMouse != lastDragAndDropCompUnderMouse)
|
||||
{
|
||||
lastDragAndDropCompUnderMouse = compUnderMouse;
|
||||
newTarget = findDragAndDropTarget (compUnderMouse, files, lastTarget);
|
||||
|
||||
if (newTarget != lastTarget)
|
||||
{
|
||||
if (lastTarget != 0)
|
||||
lastTarget->fileDragExit (files);
|
||||
|
||||
deleteAndZero (dragAndDropTargetComponent);
|
||||
|
||||
if (newTarget != 0)
|
||||
{
|
||||
Component* const targetComp = dynamic_cast <Component*> (newTarget);
|
||||
int mx = x, my = y;
|
||||
component->relativePositionToOtherComponent (targetComp, mx, my);
|
||||
|
||||
dragAndDropTargetComponent = new ComponentDeletionWatcher (dynamic_cast <Component*> (newTarget));
|
||||
newTarget->fileDragEnter (files, mx, my);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newTarget = lastTarget;
|
||||
}
|
||||
|
||||
if (newTarget != 0)
|
||||
{
|
||||
Component* const targetComp = dynamic_cast <Component*> (newTarget);
|
||||
component->relativePositionToOtherComponent (targetComp, x, y);
|
||||
|
||||
newTarget->fileDragMove (files, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentPeer::handleFileDragExit (const StringArray& files)
|
||||
{
|
||||
handleFileDragMove (files, -1, -1);
|
||||
|
||||
jassert (dragAndDropTargetComponent == 0);
|
||||
lastDragAndDropCompUnderMouse = 0;
|
||||
}
|
||||
|
||||
void ComponentPeer::handleFileDragDrop (const StringArray& files, int x, int y)
|
||||
{
|
||||
handleFileDragMove (files, x, y);
|
||||
|
||||
if (dragAndDropTargetComponent != 0 && ! dragAndDropTargetComponent->hasBeenDeleted())
|
||||
{
|
||||
FileDragAndDropTarget* const target = const_cast <FileDragAndDropTarget*> (dynamic_cast <const FileDragAndDropTarget*> (dragAndDropTargetComponent->getComponent()));
|
||||
|
||||
deleteAndZero (dragAndDropTargetComponent);
|
||||
lastDragAndDropCompUnderMouse = 0;
|
||||
|
||||
if (target != 0)
|
||||
{
|
||||
Component* const targetComp = dynamic_cast <Component*> (target);
|
||||
|
||||
if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
|
||||
{
|
||||
targetComp->internalModalInputAttempt();
|
||||
|
||||
if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
|
||||
return;
|
||||
}
|
||||
|
||||
component->relativePositionToOtherComponent (targetComp, x, y);
|
||||
target->filesDropped (files, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ComponentPeer::handleUserClosingWindow()
|
||||
{
|
||||
updateCurrentModifiers();
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class Graphics;
|
|||
#include "../../../../juce_core/text/juce_StringArray.h"
|
||||
#include "../../graphics/geometry/juce_RectangleList.h"
|
||||
class ComponentBoundsConstrainer;
|
||||
class ComponentDeletionWatcher;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -300,7 +301,9 @@ public:
|
|||
|
||||
void handleUserClosingWindow();
|
||||
|
||||
void handleFilesDropped (int x, int y, const StringArray& files);
|
||||
void handleFileDragMove (const StringArray& files, int x, int y);
|
||||
void handleFileDragExit (const StringArray& files);
|
||||
void handleFileDragDrop (const StringArray& files, int x, int y);
|
||||
|
||||
//==============================================================================
|
||||
/** Resets the masking region.
|
||||
|
|
@ -361,11 +364,15 @@ protected:
|
|||
private:
|
||||
//==============================================================================
|
||||
Component* lastFocusedComponent;
|
||||
ComponentDeletionWatcher* dragAndDropTargetComponent;
|
||||
Component* lastDragAndDropCompUnderMouse;
|
||||
bool fakeMouseMessageSent : 1, isWindowMinimised : 1;
|
||||
|
||||
friend class Component;
|
||||
static ComponentPeer* getPeerFor (const Component* const component) throw();
|
||||
|
||||
void setLastDragDropTarget (Component* comp);
|
||||
|
||||
ComponentPeer (const ComponentPeer&);
|
||||
const ComponentPeer& operator= (const ComponentPeer&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1071,7 +1071,7 @@ const String File::getRelativePathFrom (const File& dir) const throw()
|
|||
|| (commonBitLength == 1 && thisPath [1] == File::separator)
|
||||
|| (commonBitLength <= 3 && thisPath [1] == T(':')))
|
||||
#else
|
||||
if (commonBitLength <= 0
|
||||
if (commonBitLength <= 0
|
||||
|| (commonBitLength == 1 && thisPath [1] == File::separator))
|
||||
#endif
|
||||
return fullPath;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue