upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)

This commit is contained in:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -0,0 +1,493 @@
package com.roli.juce;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.InputType;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Method;
public final class ComponentPeerView extends ViewGroup
implements View.OnFocusChangeListener, Application.ActivityLifecycleCallbacks
{
public ComponentPeerView (Context context, boolean opaque_, long host)
{
super (context);
if (Application.class.isInstance (context))
{
((Application) context).registerActivityLifecycleCallbacks (this);
} else
{
((Application) context.getApplicationContext ()).registerActivityLifecycleCallbacks (this);
}
this.host = host;
setWillNotDraw (false);
opaque = opaque_;
setFocusable (true);
setFocusableInTouchMode (true);
setOnFocusChangeListener (this);
// swap red and blue colours to match internal opengl texture format
ColorMatrix colorMatrix = new ColorMatrix ();
float[] colorTransform = {0, 0, 1.0f, 0, 0,
0, 1.0f, 0, 0, 0,
1.0f, 0, 0, 0, 0,
0, 0, 0, 1.0f, 0};
colorMatrix.set (colorTransform);
paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix));
java.lang.reflect.Method method = null;
try
{
method = getClass ().getMethod ("setLayerType", int.class, Paint.class);
} catch (SecurityException e)
{
} catch (NoSuchMethodException e)
{
}
if (method != null)
{
try
{
int layerTypeNone = 0;
method.invoke (this, layerTypeNone, null);
} catch (java.lang.IllegalArgumentException e)
{
} catch (java.lang.IllegalAccessException e)
{
} catch (java.lang.reflect.InvocationTargetException e)
{
}
}
}
public void clear ()
{
host = 0;
}
//==============================================================================
private native void handlePaint (long host, Canvas canvas, Paint paint);
@Override
public void onDraw (Canvas canvas)
{
if (host == 0)
return;
handlePaint (host, canvas, paint);
}
@Override
public boolean isOpaque ()
{
return opaque;
}
private boolean opaque;
private long host;
private Paint paint = new Paint ();
//==============================================================================
private native void handleMouseDown (long host, int index, float x, float y, long time);
private native void handleMouseDrag (long host, int index, float x, float y, long time);
private native void handleMouseUp (long host, int index, float x, float y, long time);
@Override
public boolean onTouchEvent (MotionEvent event)
{
if (host == 0)
return false;
int action = event.getAction ();
long time = event.getEventTime ();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
handleMouseDown (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
return true;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
handleMouseUp (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
return true;
case MotionEvent.ACTION_MOVE:
{
handleMouseDrag (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
int n = event.getPointerCount ();
if (n > 1)
{
int point[] = new int[2];
getLocationOnScreen (point);
for (int i = 1; i < n; ++i)
handleMouseDrag (host, event.getPointerId (i), event.getX (i) + point[0], event.getY (i) + point[1], time);
}
return true;
}
case MotionEvent.ACTION_POINTER_UP:
{
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
if (i == 0)
{
handleMouseUp (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
} else
{
int point[] = new int[2];
getLocationOnScreen (point);
handleMouseUp (host, event.getPointerId (i), event.getX (i) + point[0], event.getY (i) + point[1], time);
}
return true;
}
case MotionEvent.ACTION_POINTER_DOWN:
{
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
if (i == 0)
{
handleMouseDown (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
} else
{
int point[] = new int[2];
getLocationOnScreen (point);
handleMouseDown (host, event.getPointerId (i), event.getX (i) + point[0], event.getY (i) + point[1], time);
}
return true;
}
default:
break;
}
return false;
}
//==============================================================================
private native void handleKeyDown (long host, int keycode, int textchar);
private native void handleKeyUp (long host, int keycode, int textchar);
private native void handleBackButton (long host);
private native void handleKeyboardHidden (long host);
public void showKeyboard (String type)
{
InputMethodManager imm = (InputMethodManager) getContext ().getSystemService (Context.INPUT_METHOD_SERVICE);
if (imm != null)
{
if (type.length () > 0)
{
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
imm.setInputMethod (getWindowToken (), type);
keyboardDismissListener.startListening ();
} else
{
imm.hideSoftInputFromWindow (getWindowToken (), 0);
keyboardDismissListener.stopListening ();
}
}
}
public void backButtonPressed ()
{
if (host == 0)
return;
handleBackButton (host);
}
@Override
public boolean onKeyDown (int keyCode, KeyEvent event)
{
if (host == 0)
return false;
switch (keyCode)
{
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
return super.onKeyDown (keyCode, event);
case KeyEvent.KEYCODE_BACK:
{
backButtonPressed();
return true;
}
default:
break;
}
handleKeyDown (host, keyCode, event.getUnicodeChar ());
return true;
}
@Override
public boolean onKeyUp (int keyCode, KeyEvent event)
{
if (host == 0)
return false;
handleKeyUp (host, keyCode, event.getUnicodeChar ());
return true;
}
@Override
public boolean onKeyMultiple (int keyCode, int count, KeyEvent event)
{
if (host == 0)
return false;
if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction () != KeyEvent.ACTION_MULTIPLE)
return super.onKeyMultiple (keyCode, count, event);
if (event.getCharacters () != null)
{
int utf8Char = event.getCharacters ().codePointAt (0);
handleKeyDown (host, utf8Char, utf8Char);
return true;
}
return false;
}
//==============================================================================
private final class KeyboardDismissListener
{
public KeyboardDismissListener (ComponentPeerView viewToUse)
{
view = viewToUse;
}
private void startListening ()
{
view.getViewTreeObserver ().addOnGlobalLayoutListener (viewTreeObserver);
}
private void stopListening ()
{
view.getViewTreeObserver ().removeGlobalOnLayoutListener (viewTreeObserver);
}
private class TreeObserver implements ViewTreeObserver.OnGlobalLayoutListener
{
TreeObserver ()
{
keyboardShown = false;
}
@Override
public void onGlobalLayout ()
{
Rect r = new Rect ();
View parentView = getRootView ();
int diff = 0;
if (parentView == null)
{
getWindowVisibleDisplayFrame (r);
diff = getHeight () - (r.bottom - r.top);
} else
{
parentView.getWindowVisibleDisplayFrame (r);
diff = parentView.getHeight () - (r.bottom - r.top);
}
// Arbitrary threshold, surely keyboard would take more than 20 pix.
if (diff < 20 && keyboardShown)
{
keyboardShown = false;
handleKeyboardHidden (view.host);
}
if (!keyboardShown && diff > 20)
keyboardShown = true;
}
;
private boolean keyboardShown;
}
;
private ComponentPeerView view;
private TreeObserver viewTreeObserver = new TreeObserver ();
}
private KeyboardDismissListener keyboardDismissListener = new KeyboardDismissListener (this);
// this is here to make keyboard entry work on a Galaxy Tab2 10.1
@Override
public InputConnection onCreateInputConnection (EditorInfo outAttrs)
{
outAttrs.actionLabel = "";
outAttrs.hintText = "";
outAttrs.initialCapsMode = 0;
outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
outAttrs.label = "";
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
outAttrs.inputType = InputType.TYPE_NULL;
return new BaseInputConnection (this, false);
}
//==============================================================================
@Override
protected void onSizeChanged (int w, int h, int oldw, int oldh)
{
super.onSizeChanged (w, h, oldw, oldh);
if (host != 0)
viewSizeChanged (host);
}
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
{
}
private native void viewSizeChanged (long host);
@Override
public void onFocusChange (View v, boolean hasFocus)
{
if (host == 0)
return;
if (v == this)
focusChanged (host, hasFocus);
}
private native void focusChanged (long host, boolean hasFocus);
public void setViewName (String newName)
{
}
public void setSystemUiVisibilityCompat (int visibility)
{
Method systemUIVisibilityMethod = null;
try
{
systemUIVisibilityMethod = this.getClass ().getMethod ("setSystemUiVisibility", int.class);
} catch (SecurityException e)
{
return;
} catch (NoSuchMethodException e)
{
return;
}
if (systemUIVisibilityMethod == null) return;
try
{
systemUIVisibilityMethod.invoke (this, visibility);
} catch (java.lang.IllegalArgumentException e)
{
} catch (java.lang.IllegalAccessException e)
{
} catch (java.lang.reflect.InvocationTargetException e)
{
}
}
public boolean isVisible ()
{
return getVisibility () == VISIBLE;
}
public void setVisible (boolean b)
{
setVisibility (b ? VISIBLE : INVISIBLE);
}
public boolean containsPoint (int x, int y)
{
return true; //xxx needs to check overlapping views
}
//==============================================================================
private native void handleAppPaused (long host);
private native void handleAppResumed (long host);
@Override
public void onActivityPaused (Activity activity)
{
if (host == 0)
return;
handleAppPaused (host);
}
@Override
public void onActivityStopped (Activity activity)
{
}
@Override
public void onActivitySaveInstanceState (Activity activity, Bundle bundle)
{
}
@Override
public void onActivityDestroyed (Activity activity)
{
}
@Override
public void onActivityCreated (Activity activity, Bundle bundle)
{
}
@Override
public void onActivityStarted (Activity activity)
{
}
@Override
public void onActivityResumed (Activity activity)
{
if (host == 0)
return;
// Ensure that navigation/status bar visibility is correctly restored.
handleAppResumed (host);
}
}

View File

@ -0,0 +1,136 @@
package com.roli.juce;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import java.lang.String;
public final class JuceSharingContentProvider extends ContentProvider
{
private Object lock = new Object ();
private native Cursor contentSharerQuery (Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder);
private native AssetFileDescriptor contentSharerOpenFile (Uri uri, String mode);
private native String[] contentSharerGetStreamTypes (Uri uri, String mimeTypeFilter);
public final class ProviderFileObserver extends FileObserver
{
public ProviderFileObserver (long hostToUse, String path, int mask)
{
super (path, mask);
host = hostToUse;
}
public void onEvent (int event, String path)
{
contentSharerFileObserverEvent (host, event, path);
}
private long host;
private native void contentSharerFileObserverEvent (long host, int event, String path);
}
public final class ProviderCursor extends MatrixCursor
{
ProviderCursor (long hostToUse, String[] columnNames)
{
super (columnNames);
host = hostToUse;
}
@Override
public void close ()
{
super.close ();
contentSharerCursorClosed (host);
}
private native void contentSharerCursorClosed (long host);
private long host;
}
@Override
public boolean onCreate ()
{
return true;
}
@Override
public Cursor query (Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
synchronized (lock)
{
return contentSharerQuery (url, projection, selection, selectionArgs, sortOrder);
}
}
@Override
public Uri insert (Uri uri, ContentValues values)
{
return null;
}
@Override
public int update (Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
return 0;
}
@Override
public int delete (Uri uri, String selection, String[] selectionArgs)
{
return 0;
}
@Override
public String getType (Uri uri)
{
return null;
}
@Override
public AssetFileDescriptor openAssetFile (Uri uri, String mode)
{
synchronized (lock)
{
return contentSharerOpenFile (uri, mode);
}
}
@Override
public ParcelFileDescriptor openFile (Uri uri, String mode)
{
synchronized (lock)
{
AssetFileDescriptor result = contentSharerOpenFile (uri, mode);
if (result != null)
return result.getParcelFileDescriptor ();
return null;
}
}
public String[] getStreamTypes (Uri uri, String mimeTypeFilter)
{
synchronized (lock)
{
return contentSharerGetStreamTypes (uri, mimeTypeFilter);
}
}
}

View File

@ -23,55 +23,93 @@
==============================================================================
*/
namespace juce
{
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
FIELD (providers, "providers", "[Landroid/content/pm/ProviderInfo;")
//==============================================================================
// This byte-code is generated from native/javacore/app/com/roli/juce/JuceSharingContentProvider.java with min sdk version 16
// See juce_core/native/java/README.txt on how to generate this byte-code.
static const uint8 javaJuceSharingContentProvider[] =
{31,139,8,8,143,106,229,91,0,3,74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,
101,114,46,100,101,120,0,149,151,93,108,20,85,20,199,207,157,153,157,253,236,178,91,170,20,145,178,229,83,80,216,242,165,
96,5,11,45,72,183,91,139,161,52,218,190,56,221,157,148,129,221,153,101,102,118,133,23,2,106,162,209,196,24,125,64,19,73,
48,33,106,140,15,36,26,227,131,49,152,24,163,241,65,77,148,248,160,209,152,152,24,193,68,227,131,6,37,241,127,63,118,219,
173,197,232,194,111,238,185,231,156,123,238,185,231,222,153,206,148,237,19,137,190,173,219,105,239,208,216,231,67,47,106,
177,200,154,39,135,207,172,189,226,63,113,230,173,189,99,175,63,244,123,185,131,168,70,68,39,38,182,117,146,250,157,79,
17,141,146,212,223,4,46,48,34,110,252,3,109,4,237,103,26,209,82,222,71,171,163,189,132,203,80,156,40,103,16,125,111,18,
253,4,126,6,191,129,107,224,58,232,137,18,245,130,53,96,3,216,2,14,131,6,120,25,188,11,190,1,191,128,100,140,104,19,112,
192,235,224,50,184,6,110,193,28,187,192,3,192,6,117,240,52,120,6,60,15,206,130,115,224,101,240,10,120,3,188,9,222,6,159,
128,175,192,183,224,42,136,38,136,214,129,33,48,5,60,240,8,56,5,206,130,87,193,69,240,54,120,31,124,12,62,5,95,130,31,
192,21,240,43,248,19,24,73,162,197,96,57,88,5,242,224,78,176,27,12,131,7,65,9,56,224,56,56,9,78,129,199,192,83,0,101,37,
148,142,16,138,208,37,148,159,176,45,148,6,139,64,6,100,73,238,193,98,208,165,246,229,102,176,4,116,147,220,143,91,193,
106,176,134,228,190,240,223,195,168,189,166,228,10,228,152,154,235,4,100,148,65,236,231,105,165,71,233,233,89,200,248,47,
108,252,23,83,50,247,143,170,60,94,48,229,92,205,3,179,92,201,231,249,62,43,249,53,200,43,148,124,17,242,42,37,191,11,
121,165,146,63,130,220,171,228,47,32,231,148,252,181,41,215,177,120,78,14,93,42,135,4,170,181,85,212,42,69,247,137,122,
201,126,82,245,83,168,214,157,196,215,28,19,99,13,172,176,143,248,154,22,137,190,9,253,58,17,51,45,250,9,81,105,222,74,
125,2,255,214,171,120,36,218,36,109,16,109,156,238,17,241,101,220,20,42,113,187,104,53,186,67,180,58,109,20,45,163,77,
202,190,89,180,81,218,34,90,131,182,171,252,250,213,184,93,162,53,105,183,26,191,71,237,253,1,177,231,49,149,151,172,185,
169,106,193,247,171,15,157,109,50,61,113,94,178,170,70,77,251,0,236,35,202,158,82,118,109,142,253,32,236,211,202,206,245,
157,144,187,83,179,114,111,74,158,201,13,41,238,31,17,250,231,146,114,142,41,198,168,150,211,104,128,38,53,126,66,117,
120,242,179,118,46,41,207,137,151,209,225,127,8,91,89,235,139,146,198,210,34,119,83,248,92,104,197,208,97,53,104,32,50,
169,105,136,17,129,149,231,117,49,41,215,121,8,241,107,227,113,210,54,167,17,139,137,92,222,73,202,181,214,50,60,183,149,
168,79,45,195,207,253,84,198,16,59,25,17,167,154,232,189,164,90,7,246,155,199,229,249,125,152,148,117,24,239,53,104,57,
171,245,165,104,139,145,162,30,150,197,222,247,176,117,34,183,152,152,39,78,186,170,212,103,173,56,89,68,150,119,211,229,
57,58,77,100,133,103,86,83,151,153,157,239,251,121,243,117,252,203,124,166,26,115,37,41,239,233,241,45,24,163,241,49,131,
145,20,237,128,159,155,225,51,165,88,143,150,101,157,184,222,118,189,3,215,117,76,222,227,89,17,167,19,126,188,202,140,
174,183,205,221,48,121,5,111,60,119,68,172,33,158,154,173,89,206,160,182,223,29,243,250,59,230,245,121,55,138,168,89,220,
161,186,144,179,226,94,213,148,28,17,109,151,208,102,91,122,93,84,47,218,58,151,89,209,231,232,170,205,170,216,252,126,
202,42,61,151,155,177,179,202,175,139,204,123,28,215,9,119,19,27,38,99,184,88,44,82,132,95,139,196,10,180,162,80,47,217,
135,142,88,190,227,206,12,122,110,104,187,225,65,223,107,56,101,219,223,116,212,106,88,196,138,164,193,85,231,254,102,81,
252,168,183,104,185,101,223,115,202,249,146,28,146,159,55,180,159,86,220,200,101,194,170,212,237,160,159,214,255,195,193,
183,131,252,158,32,176,195,253,78,197,30,178,131,146,239,212,66,15,177,150,182,92,203,86,104,77,91,129,157,31,172,251,
129,215,54,77,203,52,106,133,190,115,162,233,144,109,57,184,118,152,63,236,59,115,195,121,65,158,207,53,54,29,216,126,
131,103,221,59,215,116,208,242,75,118,101,126,50,59,139,37,175,154,247,189,138,147,63,138,210,229,111,92,191,213,77,161,
153,203,189,255,127,104,123,122,27,254,115,128,126,90,89,44,91,149,134,115,44,111,185,174,23,90,161,227,185,249,125,110,
169,226,5,220,187,98,5,216,131,158,5,124,134,93,23,25,75,123,239,2,246,81,187,58,173,28,248,54,118,22,249,41,201,87,44,
119,38,63,54,125,212,46,133,237,186,67,33,207,174,159,210,237,197,160,174,133,86,72,108,130,244,137,97,156,184,137,2,25,
19,5,33,225,236,77,20,113,112,39,138,5,28,92,126,29,38,54,73,139,167,22,152,37,105,149,74,118,16,236,175,88,51,1,69,248,
98,109,74,150,188,74,189,234,222,111,85,237,128,150,170,195,198,171,214,204,101,144,187,149,169,167,205,52,55,173,125,13,
168,105,89,155,253,62,59,196,164,182,85,29,63,89,67,220,155,218,140,99,53,219,229,1,168,179,77,253,64,221,246,79,146,89,
182,43,118,104,83,196,22,97,151,204,216,225,66,39,141,210,51,237,83,68,209,231,18,25,71,188,32,164,56,191,142,123,135,
177,66,211,113,145,104,72,70,197,43,29,35,163,106,5,199,40,93,117,170,54,119,71,212,16,149,53,170,94,25,67,93,84,129,98,
158,59,136,184,200,33,234,185,114,113,29,30,82,110,221,124,240,104,174,192,168,89,225,17,74,212,124,143,239,45,14,0,69,
142,203,101,224,118,173,87,144,71,128,229,72,75,71,75,220,227,163,254,113,212,54,28,243,203,124,246,240,136,19,144,201,
175,171,251,200,172,215,202,124,118,189,238,59,252,82,161,72,131,63,21,200,20,77,64,155,244,3,219,215,71,211,27,119,109,
164,187,40,154,222,53,73,203,140,3,219,7,118,72,213,42,173,111,32,154,158,196,147,24,38,178,244,194,208,190,104,154,30,
99,90,97,39,20,14,205,176,2,250,227,90,97,20,205,16,156,168,170,21,238,22,166,134,20,138,58,254,116,108,156,26,193,147,
119,36,50,178,103,104,223,126,97,157,50,10,163,34,150,214,193,70,186,83,90,90,91,107,100,239,94,114,75,83,88,166,45,98,
35,183,106,221,137,238,36,105,26,195,159,238,103,115,145,211,167,141,75,49,237,81,141,76,246,93,140,171,53,174,142,157,
57,109,60,30,103,80,39,216,133,56,49,35,110,104,73,232,46,9,93,147,69,236,199,56,99,127,129,139,9,198,62,0,95,129,171,
224,124,146,177,31,193,75,41,249,110,75,234,89,222,108,155,223,30,252,57,223,252,254,208,105,246,27,196,160,217,239,16,
222,54,191,69,76,154,253,30,209,51,82,230,127,207,88,78,190,75,15,64,54,115,82,207,223,161,88,70,190,103,139,119,228,156,
156,151,127,191,232,202,159,191,243,24,57,57,31,127,47,34,53,86,188,123,101,100,174,252,91,233,111,138,244,241,33,100,13,
0,0};
DECLARE_JNI_CLASS (AndroidPackageInfo, "android/content/pm/PackageInfo");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
FIELD (authority, "authority", "Ljava/lang/String;")
DECLARE_JNI_CLASS (AndroidProviderInfo, "android/content/pm/ProviderInfo");
DECLARE_JNI_CLASS (AndroidProviderInfo, "android/content/pm/ProviderInfo")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (constructor, "<init>", "(Landroid/os/ParcelFileDescriptor;JJ)V") \
METHOD (createInputStream, "createInputStream", "()Ljava/io/FileInputStream;") \
METHOD (getLength, "getLength", "()J")
DECLARE_JNI_CLASS (AssetFileDescriptor, "android/content/res/AssetFileDescriptor");
DECLARE_JNI_CLASS (AssetFileDescriptor, "android/content/res/AssetFileDescriptor")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (close, "close", "()V")
DECLARE_JNI_CLASS (JavaCloseable, "java/io/Closeable");
DECLARE_JNI_CLASS (JavaCloseable, "java/io/Closeable")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(L" JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSPATH ";JLjava/lang/String;I)V") \
METHOD (startWatching, "startWatching", "()V") \
METHOD (stopWatching, "stopWatching", "()V")
DECLARE_JNI_CLASS (JuceContentProviderFileObserver, JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSPATH "$ProviderFileObserver");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (addRow, "addRow", "([Ljava/lang/Object;)V") \
METHOD (constructor, "<init>", "(L" JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSPATH ";J[Ljava/lang/String;)V")
DECLARE_JNI_CLASS (JuceContentProviderFileObserverCursor, JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSPATH "$ProviderCursor");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
STATICMETHOD (open, "open", "(Ljava/io/File;I)Landroid/os/ParcelFileDescriptor;")
DECLARE_JNI_CLASS (ParcelFileDescriptor, "android/os/ParcelFileDescriptor");
DECLARE_JNI_CLASS (ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
#undef JNI_CLASS_MEMBERS
//==============================================================================
@ -90,8 +128,8 @@ public:
const LocalRef<jobject>& contentProvider,
const LocalRef<jobjectArray>& resultColumns)
: owner (ownerToUse),
cursor (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderFileObserverCursor,
JuceContentProviderFileObserverCursor.constructor,
cursor (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderCursor,
JuceContentProviderCursor.constructor,
contentProvider.get(),
reinterpret_cast<jlong> (this),
resultColumns.get()))))
@ -107,11 +145,35 @@ public:
MessageManager::callAsync ([this] { owner.cursorClosed (*this); });
}
void addRow (LocalRef<jobjectArray>& values)
{
auto* env = getEnv();
env->CallVoidMethod (cursor.get(), JuceContentProviderCursor.addRow, values.get());
}
private:
Owner& owner;
GlobalRef cursor;
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (addRow, "addRow", "([Ljava/lang/Object;)V") \
METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;J[Ljava/lang/String;)V") \
CALLBACK (contentSharerCursorClosed, "contentSharerCursorClosed", "(J)V") \
DECLARE_JNI_CLASS (JuceContentProviderCursor, "com/roli/juce/JuceSharingContentProvider$ProviderCursor")
#undef JNI_CLASS_MEMBERS
static void JNICALL contentSharerCursorClosed(JNIEnv*, jobject, jlong host)
{
if (auto* myself = reinterpret_cast<AndroidContentSharerCursor*> (host))
myself->cursorClosed();
}
};
AndroidContentSharerCursor::JuceContentProviderCursor_Class AndroidContentSharerCursor::JuceContentProviderCursor;
//==============================================================================
class AndroidContentSharerFileObserver
{
@ -182,8 +244,26 @@ private:
Owner& owner;
String filepath;
GlobalRef fileObserver;
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;JLjava/lang/String;I)V") \
METHOD (startWatching, "startWatching", "()V") \
METHOD (stopWatching, "stopWatching", "()V") \
CALLBACK (contentSharerFileObserverEvent, "contentSharerFileObserverEvent", "(JILjava/lang/String;)V") \
DECLARE_JNI_CLASS (JuceContentProviderFileObserver, "com/roli/juce/JuceSharingContentProvider$ProviderFileObserver")
#undef JNI_CLASS_MEMBERS
static void JNICALL contentSharerFileObserverEvent (JNIEnv*, jobject /*fileObserver*/, jlong host, int event, jstring path)
{
if (auto* myself = reinterpret_cast<AndroidContentSharerFileObserver*> (host))
myself->onFileEvent (event, LocalRef<jstring> (path));
}
};
AndroidContentSharerFileObserver::JuceContentProviderFileObserver_Class AndroidContentSharerFileObserver::JuceContentProviderFileObserver;
//==============================================================================
class AndroidContentSharerPrepareFilesThread : private Thread
{
@ -220,7 +300,7 @@ public:
private:
struct StreamCloser
{
StreamCloser (jobject streamToUse)
StreamCloser (const LocalRef<jobject>& streamToUse)
: stream (GlobalRef (streamToUse))
{
}
@ -289,12 +369,12 @@ private:
URL copyAssetFileToTemporaryFile (JNIEnv* env, const String& filename)
{
auto resources = LocalRef<jobject> (env->CallObjectMethod (android.activity, JuceAppActivity.getResources));
auto resources = LocalRef<jobject> (env->CallObjectMethod (getAppContext().get(), AndroidContext.getResources));
int fileId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (filename).get(),
javaString ("raw").get(), javaString (packageName).get());
// Raw resource not found. Please make sure that you include your file as a raw resource
// and that you specify just the file name, without an extention.
// and that you specify just the file name, without an extension.
jassert (fileId != 0);
if (fileId == 0)
@ -307,14 +387,10 @@ private:
auto inputStream = StreamCloser (LocalRef<jobject> (env->CallObjectMethod (assetFd,
AssetFileDescriptor.createInputStream)));
auto exception = LocalRef<jobject> (env->ExceptionOccurred());
if (exception != 0)
if (jniCheckHasExceptionOccurredAndClear())
{
// Failed to open file stream for resource
jassertfalse;
env->ExceptionClear();
return {};
}
@ -326,35 +402,27 @@ private:
JavaFileOutputStream.constructor,
javaString (tempFile.getFullPathName()).get())));
exception = LocalRef<jobject> (env->ExceptionOccurred());
if (exception != 0)
if (jniCheckHasExceptionOccurredAndClear())
{
// Failed to open file stream for temporary file
jassertfalse;
env->ExceptionClear();
return {};
}
auto buffer = LocalRef<jbyteArray> (env->NewByteArray (1024));
int bytesRead = 0;
while (true)
for (;;)
{
if (threadShouldExit())
return {};
bytesRead = env->CallIntMethod (inputStream.stream, JavaFileInputStream.read, buffer.get());
exception = LocalRef<jobject> (env->ExceptionOccurred());
if (exception != 0)
if (jniCheckHasExceptionOccurredAndClear())
{
// Failed to read from resource file.
jassertfalse;
env->ExceptionClear();
return {};
}
@ -363,12 +431,10 @@ private:
env->CallVoidMethod (outputStream.stream, JavaFileOutputStream.write, buffer.get(), 0, bytesRead);
if (exception != 0)
if (jniCheckHasExceptionOccurredAndClear())
{
// Failed to write to temporary file.
jassertfalse;
env->ExceptionClear();
return {};
}
}
@ -400,8 +466,7 @@ class ContentSharer::ContentSharerNativeImpl : public ContentSharer::Pimpl,
public:
ContentSharerNativeImpl (ContentSharer& cs)
: owner (cs),
packageName (juceString (LocalRef<jstring> ((jstring) getEnv()->CallObjectMethod (android.activity,
JuceAppActivity.getPackageName)))),
packageName (juceString (LocalRef<jstring> ((jstring) getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageName)))),
uriBase ("content://" + packageName + ".sharingcontentprovider/")
{
}
@ -445,7 +510,14 @@ public:
auto chooserIntent = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidIntent, AndroidIntent.createChooser,
intent.get(), javaString ("Choose share target").get()));
env->CallVoidMethod (android.activity, JuceAppActivity.startActivityForResult, chooserIntent.get(), 1003);
WeakReference<ContentSharerNativeImpl> weakRef (this);
startAndroidActivityForResult (chooserIntent, 1003,
[weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
{
if (weakRef != nullptr)
weakRef->sharingFinished (resultCode);
});
}
//==============================================================================
@ -460,7 +532,7 @@ public:
}
//==============================================================================
void* openFile (const LocalRef<jobject>& contentProvider,
jobject openFile (const LocalRef<jobject>& contentProvider,
const LocalRef<jobject>& uri, const LocalRef<jstring>& mode)
{
ignoreUnused (mode);
@ -480,7 +552,7 @@ public:
return getAssetFileDescriptor (env, contentProvider, uriElements.filepath);
}
void* query (const LocalRef<jobject>& contentProvider, const LocalRef<jobject>& uri,
jobject query (const LocalRef<jobject>& contentProvider, const LocalRef<jobject>& uri,
const LocalRef<jobjectArray>& projection, const LocalRef<jobject>& selection,
const LocalRef<jobjectArray>& selectionArgs, const LocalRef<jobject>& sortOrder)
{
@ -535,13 +607,11 @@ public:
}
}
auto nativeCursor = cursor->getNativeCursor();
env->CallVoidMethod (nativeCursor, JuceContentProviderFileObserverCursor.addRow, values.get());
return nativeCursor;
cursor->addRow (values);
return cursor->getNativeCursor();
}
void* getStreamTypes (const LocalRef<jobject>& uri, const LocalRef<jstring>& mimeTypeFilter)
jobjectArray getStreamTypes (const LocalRef<jobject>& uri, const LocalRef<jstring>& mimeTypeFilter)
{
auto* env = getEnv();
@ -572,8 +642,7 @@ private:
{
auto* env = getEnv();
auto packageManager = LocalRef<jobject> (env->CallObjectMethod (android.activity,
JuceAppActivity.getPackageManager));
LocalRef<jobject> packageManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageManager));
constexpr int getProviders = 8;
auto packageInfo = LocalRef<jobject> (env->CallObjectMethod (packageManager,
@ -634,8 +703,14 @@ private:
AndroidIntent.createChooser,
intent.get(),
javaString ("Choose share target").get()));
WeakReference<ContentSharerNativeImpl> weakRef (this);
env->CallVoidMethod (android.activity, JuceAppActivity.startActivityForResult, chooserIntent.get(), 1003);
startAndroidActivityForResult (chooserIntent, 1003,
[weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
{
if (weakRef != nullptr)
weakRef->sharingFinished (resultCode);
});
}
void decrementPendingFileCountAndNotifyOwnerIfReady()
@ -688,7 +763,7 @@ private:
return StringArray ("_display_name", "_size");
}
void* getAssetFileDescriptor (JNIEnv* env, const LocalRef<jobject>& contentProvider,
jobject getAssetFileDescriptor (JNIEnv* env, const LocalRef<jobject>& contentProvider,
const String& filepath)
{
// This function can be called from multiple threads.
@ -714,14 +789,10 @@ private:
ParcelFileDescriptor.open,
javaFile.get(), modeReadOnly));
auto exception = LocalRef<jobject> (env->ExceptionOccurred());
if (exception != 0)
if (jniCheckHasExceptionOccurredAndClear())
{
// Failed to create file descriptor. Have you provided a valid file path/resource name?
jassertfalse;
env->ExceptionClear();
return nullptr;
}
@ -758,6 +829,51 @@ private:
WeakReference<ContentSharerNativeImpl>::Master masterReference;
friend class WeakReference<ContentSharerNativeImpl>;
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
CALLBACK (contentSharerQuery, "contentSharerQuery", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;") \
CALLBACK (contentSharerOpenFile, "contentSharerOpenFile", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;") \
CALLBACK (contentSharerGetStreamTypes, "contentSharerGetStreamTypes", "(Landroid/net/Uri;Ljava/lang/String;)[Ljava/lang/String;") \
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceSharingContentProvider, "com/roli/juce/JuceSharingContentProvider", 16, javaJuceSharingContentProvider, sizeof(javaJuceSharingContentProvider))
#undef JNI_CLASS_MEMBERS
static jobject JNICALL contentSharerQuery (JNIEnv*, jobject contentProvider, jobject uri, jobjectArray projection,
jobject selection, jobjectArray selectionArgs, jobject sortOrder)
{
if (auto *pimpl = (ContentSharer::ContentSharerNativeImpl *) ContentSharer::getInstance ()->pimpl.get ())
return pimpl->query (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jobjectArray> (
static_cast<jobjectArray> (projection)),
LocalRef<jobject> (static_cast<jobject> (selection)),
LocalRef<jobjectArray> (
static_cast<jobjectArray> (selectionArgs)),
LocalRef<jobject> (static_cast<jobject> (sortOrder)));
return nullptr;
}
static jobject JNICALL contentSharerOpenFile (JNIEnv*, jobject contentProvider, jobject uri, jstring mode)
{
if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
return pimpl->openFile (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jstring> (static_cast<jstring> (mode)));
return nullptr;
}
static jobjectArray JNICALL contentSharerGetStreamTypes (JNIEnv*, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter)
{
if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
return pimpl->getStreamTypes (LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jstring> (static_cast<jstring> (mimeTypeFilter)));
return nullptr;
}
};
//==============================================================================
@ -766,81 +882,6 @@ ContentSharer::Pimpl* ContentSharer::createPimpl()
return new ContentSharerNativeImpl (*this);
}
//==============================================================================
void* juce_contentSharerQuery (void* contentProvider, void* uri, void* projection,
void* selection, void* selectionArgs, void* sortOrder)
{
auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get();
return pimpl->query (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jobjectArray> (static_cast<jobjectArray> (projection)),
LocalRef<jobject> (static_cast<jobject> (selection)),
LocalRef<jobjectArray> (static_cast<jobjectArray> (selectionArgs)),
LocalRef<jobject> (static_cast<jobject> (sortOrder)));
}
void* juce_contentSharerOpenFile (void* contentProvider, void* uri, void* mode)
{
auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get();
return pimpl->openFile (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jstring> (static_cast<jstring> (mode)));
}
void juce_contentSharingCompleted (int resultCode)
{
auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get();
return pimpl->sharingFinished (resultCode);
}
void* juce_contentSharerGetStreamTypes (void* uri, void* mimeTypeFilter)
{
auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get();
return pimpl->getStreamTypes (LocalRef<jobject> (static_cast<jobject> (uri)),
LocalRef<jstring> (static_cast<jstring> (mimeTypeFilter)));
}
//==============================================================================
JUCE_JNI_CALLBACK (JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSNAME, contentSharerFileObserverEvent, void,
(JNIEnv* env, jobject /*fileObserver*/, jlong host, int event, jstring path))
{
setEnv (env);
reinterpret_cast<AndroidContentSharerFileObserver*> (host)->onFileEvent (event, LocalRef<jstring> (path));
}
//==============================================================================
JUCE_JNI_CALLBACK (JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSNAME, contentSharerQuery, jobject,
(JNIEnv* env, jobject contentProvider, jobject uri, jobjectArray projection,
jobject selection, jobjectArray selectionArgs, jobject sortOrder))
{
setEnv (env);
return (jobject) juce_contentSharerQuery (contentProvider, uri, projection, selection, selectionArgs, sortOrder);
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSNAME, contentSharerCursorClosed, void,
(JNIEnv* env, jobject /*cursor*/, jlong host))
{
setEnv (env);
reinterpret_cast<AndroidContentSharerCursor*> (host)->cursorClosed();
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSNAME, contentSharerOpenFile, jobject,
(JNIEnv* env, jobject contentProvider, jobject uri, jstring mode))
{
setEnv (env);
return (jobject) juce_contentSharerOpenFile ((void*) contentProvider, (void*) uri, (void*) mode);
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_SHARING_CONTENT_PROVIDER_CLASSNAME, contentSharerGetStreamTypes, jobject,
(JNIEnv* env, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter))
{
setEnv (env);
return (jobject) juce_contentSharerGetStreamTypes ((void*) uri, (void*) mimeTypeFilter);
}
ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider_Class ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider;
} // namespace juce

View File

@ -30,6 +30,7 @@ namespace juce
class FileChooser::Native : public FileChooser::Pimpl
{
public:
//==============================================================================
Native (FileChooser& fileChooser, int flags) : owner (fileChooser)
{
if (currentFileChooser == nullptr)
@ -37,7 +38,7 @@ public:
currentFileChooser = this;
auto* env = getEnv();
auto sdkVersion = env->CallStaticIntMethod (JuceAppActivity, JuceAppActivity.getAndroidSDKVersion);
auto sdkVersion = getAndroidSDKVersion();
auto saveMode = ((flags & FileBrowserComponent::saveMode) != 0);
auto selectsDirectories = ((flags & FileBrowserComponent::canSelectDirectories) != 0);
@ -64,8 +65,8 @@ public:
: "android.intent.action.GET_CONTENT")));
intent = GlobalRef (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
javaString (action).get()));
intent = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
javaString (action).get())));
if (owner.startingFile != File())
{
@ -135,6 +136,7 @@ public:
~Native()
{
masterReference.clear();
currentFileChooser = nullptr;
}
@ -146,13 +148,26 @@ public:
void launch() override
{
auto* env = getEnv();
if (currentFileChooser != nullptr)
android.activity.callVoidMethod (JuceAppActivity.startActivityForResult, intent.get(), /*READ_REQUEST_CODE*/ 42);
{
WeakReference<Native> myself (this);
startAndroidActivityForResult (LocalRef<jobject> (env->NewLocalRef (intent.get())), /*READ_REQUEST_CODE*/ 42,
[myself] (int requestCode, int resultCode, LocalRef<jobject> intentData) mutable
{
if (myself != nullptr)
myself->onActivityResult (requestCode, resultCode, intentData);
});
}
else
{
jassertfalse; // There is already a file chooser running
}
}
void completed (int resultCode, jobject intentData)
void onActivityResult (int /*requestCode*/, int resultCode, const LocalRef<jobject>& intentData)
{
currentFileChooser = nullptr;
auto* env = getEnv();
@ -161,7 +176,7 @@ public:
if (resultCode == /*Activity.RESULT_OK*/ -1 && intentData != nullptr)
{
LocalRef<jobject> uri (env->CallObjectMethod (intentData, AndroidIntent.getData));
LocalRef<jobject> uri (env->CallObjectMethod (intentData.get(), AndroidIntent.getData));
if (uri != nullptr)
{
@ -197,23 +212,23 @@ public:
}
private:
JUCE_DECLARE_WEAK_REFERENCEABLE (Native)
FileChooser& owner;
GlobalRef intent;
};
FileChooser::Native* FileChooser::Native::currentFileChooser = nullptr;
void juce_fileChooserCompleted (int resultCode, void* intentData)
{
if (FileChooser::Native::currentFileChooser != nullptr)
FileChooser::Native::currentFileChooser->completed (resultCode, (jobject) intentData);
}
FileChooser::Pimpl* FileChooser::showPlatformDialog (FileChooser& owner, int flags,
FilePreviewComponent*)
{
return new FileChooser::Native (owner, flags);
if (FileChooser::Native::currentFileChooser == nullptr)
return new FileChooser::Native (owner, flags);
// there can only be one file chooser on Android at a once
jassertfalse;
return nullptr;
}
bool FileChooser::isPlatformDialogAvailable()

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ struct MimeTypeTableEntry
{
const char* fileExtension, *mimeType;
static MimeTypeTableEntry table[640];
static MimeTypeTableEntry table[641];
};
static StringArray getMimeTypesForFileExtension (const String& fileExtension)
@ -88,7 +88,7 @@ static String getCommonMimeType (const StringArray& mimeTypes)
}
//==============================================================================
MimeTypeTableEntry MimeTypeTableEntry::table[640] =
MimeTypeTableEntry MimeTypeTableEntry::table[641] =
{
{"3dm", "x-world/x-3dmf"},
{"3dmf", "x-world/x-3dmf"},
@ -384,6 +384,7 @@ MimeTypeTableEntry MimeTypeTableEntry::table[640] =
{"mp2", "video/mpeg"},
{"mp2", "video/x-mpeg"},
{"mp2", "video/x-mpeq2a"},
{"mp3", "audio/mpeg"},
{"mp3", "audio/mpeg3"},
{"mp3", "audio/x-mpeg-3"},
{"mp3", "video/mpeg"},
@ -477,7 +478,7 @@ MimeTypeTableEntry MimeTypeTableEntry::table[640] =
{"pvu", "paleovu/x-pv"},
{"pwz", "application/vnd.ms-powerpoint"},
{"py", "text/x-script.phyton"},
{"pyc", "applicaiton/x-bytecode.python"},
{"pyc", "application/x-bytecode.python"},
{"qcp", "audio/vnd.qcelp"},
{"qd3", "x-world/x-3dmf"},
{"qd3d", "x-world/x-3dmf"},

View File

@ -45,7 +45,7 @@ public:
void shareFiles (const Array<URL>& files) override
{
auto* urls = [NSMutableArray arrayWithCapacity: (NSUInteger) files.size()];
auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) files.size()];
for (const auto& f : files)
{
@ -86,7 +86,7 @@ public:
void shareText (const String& text) override
{
auto* array = [NSArray arrayWithObject: juceStringToNS (text)];
auto array = [NSArray arrayWithObject: juceStringToNS (text)];
share (array);
}

View File

@ -85,11 +85,34 @@ public:
setOpaque (false);
auto chooserBounds = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
setBounds (chooserBounds);
if (SystemStats::isRunningInAppExtensionSandbox())
{
if (fileChooser.parent != nullptr)
{
[controller.get() setModalPresentationStyle:UIModalPresentationFullScreen];
setAlwaysOnTop (true);
addToDesktop (0);
auto chooserBounds = fileChooser.parent->getBounds();
setBounds (chooserBounds);
setAlwaysOnTop (true);
fileChooser.parent->addAndMakeVisible (this);
}
else
{
// Opening a native top-level window in an AUv3 is not allowed (sandboxing). You need to specify a
// parent component (for example your editor) to parent the native file chooser window. To do this
// specify a parent component in the FileChooser's constructor!
jassert (fileChooser.parent != nullptr);
}
}
else
{
auto chooserBounds = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
setBounds (chooserBounds);
setAlwaysOnTop (true);
addToDesktop (0);
}
}
~Native()
@ -199,7 +222,7 @@ private:
NSArray<NSFileAccessIntent*>* intents = @[fileAccessIntent];
auto* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter: nil];
auto fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter: nil];
[fileCoordinator coordinateAccessWithIntents: intents queue: [NSOperationQueue mainQueue] byAccessor: ^(NSError* err)
{
@ -228,7 +251,7 @@ private:
}
else
{
auto* desc = [error localizedDescription];
auto desc = [error localizedDescription];
ignoreUnused (desc);
jassertfalse;
}
@ -237,7 +260,7 @@ private:
}
else
{
auto* desc = [err localizedDescription];
auto desc = [err localizedDescription];
ignoreUnused (desc);
jassertfalse;
}
@ -308,7 +331,7 @@ bool FileChooser::isPlatformDialogAvailable()
#if JUCE_DISABLE_NATIVE_FILECHOOSERS
return false;
#else
return [[NSFileManager defaultManager] ubiquityIdentityToken] != nil;
return true;
#endif
}

View File

@ -163,8 +163,17 @@ using namespace juce;
namespace juce
{
struct UIViewPeerControllerReceiver
{
virtual ~UIViewPeerControllerReceiver();
virtual void setViewController (UIViewController*) = 0;
};
UIViewPeerControllerReceiver::~UIViewPeerControllerReceiver() {}
class UIViewComponentPeer : public ComponentPeer,
public FocusChangeListener
public FocusChangeListener,
public UIViewPeerControllerReceiver
{
public:
UIViewComponentPeer (Component&, int windowStyleFlags, UIView* viewToAttachTo);
@ -176,6 +185,12 @@ public:
void setTitle (const String& title) override;
void setBounds (const Rectangle<int>&, bool isNowFullScreen) override;
void setViewController (UIViewController* newController) override
{
jassert (controller == nullptr);
controller = [newController retain];
}
Rectangle<int> getBounds() const override { return getBounds (! isSharedWindow); }
Rectangle<int> getBounds (bool global) const;
Point<float> localToGlobal (Point<float> relativePosition) override;
@ -218,7 +233,7 @@ public:
//==============================================================================
UIWindow* window;
JuceUIView* view;
JuceUIViewController* controller;
UIViewController* controller;
bool isSharedWindow, fullScreen, insideDrawRect, isAppex;
static int64 getMouseTime (UIEvent* e) noexcept
@ -375,6 +390,13 @@ MultiTouchMapper<UITouch*> UIViewComponentPeer::currentTouches;
return isKioskModeView (self);
}
#if defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
- (BOOL) prefersHomeIndicatorAutoHidden
{
return isKioskModeView (self);
}
#endif
- (UIStatusBarStyle) preferredStatusBarStyle
{
return UIStatusBarStyleDefault;
@ -702,7 +724,7 @@ void UIViewComponentPeer::updateTransformAndScreenBounds()
const Rectangle<int> oldArea (component.getBounds());
const Rectangle<int> oldDesktop (desktop.getDisplays().getMainDisplay().userArea);
const_cast<Desktop::Displays&> (desktop.getDisplays()).refresh();
const_cast<Displays&> (desktop.getDisplays()).refresh();
window.transform = Orientations::getCGTransformFor (desktop.getCurrentOrientation());
view.transform = CGAffineTransformIdentity;

View File

@ -48,7 +48,8 @@ namespace juce
}
@property (strong, nonatomic) UIWindow *window;
- (id)init;
- (id) init;
- (void) dealloc;
- (void) applicationDidFinishLaunching: (UIApplication*) application;
- (void) applicationWillTerminate: (UIApplication*) application;
- (void) applicationDidEnterBackground: (UIApplication*) application;
@ -88,7 +89,7 @@ namespace juce
NSObject* _pushNotificationsDelegate;
- (id)init
- (id) init
{
self = [super init];
appSuspendTask = UIBackgroundTaskInvalid;
@ -100,6 +101,11 @@ namespace juce
return self;
}
- (void) dealloc
{
[super dealloc];
}
- (void) applicationDidFinishLaunching: (UIApplication*) application
{
ignoreUnused (application);
@ -640,13 +646,13 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*i
}
//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool, Component*)
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool, Component*, std::function<void()>)
{
jassertfalse; // no such thing on iOS!
return false;
}
bool DragAndDropContainer::performExternalDragDropOfText (const String&, Component*)
bool DragAndDropContainer::performExternalDragDropOfText (const String&, Component*, std::function<void()>)
{
jassertfalse; // no such thing on iOS!
return false;
@ -730,7 +736,7 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
return Orientations::convertToJuce (orientation);
}
void Desktop::Displays::findDisplays (float masterScale)
void Displays::findDisplays (float masterScale)
{
JUCE_AUTORELEASEPOOL
{

File diff suppressed because it is too large Load Diff

View File

@ -128,7 +128,7 @@ public:
#endif
}
~Native()
~Native() override
{
exitModalState (0);
removeFromDesktop();
@ -188,6 +188,14 @@ public:
finished (result);
}
bool canModalEventBeSentToComponent (const Component* targetComponent) override
{
if (targetComponent == nullptr)
return false;
return targetComponent->findParentComponentOfClass<FilePreviewComponent>() != nullptr;
}
private:
//==============================================================================
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@ -202,13 +210,22 @@ private:
exitModalState (0);
if (panel != nil && result == NSFileHandlingPanelOKButton)
if (panel != nil && result ==
#if defined (MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
NSModalResponseOK)
#else
NSFileHandlingPanelOKButton)
#endif
{
auto addURLResult = [&chooserResults] (NSURL* urlToAdd)
{
auto scheme = nsStringToJuce ([urlToAdd scheme]);
auto path = nsStringToJuce ([urlToAdd path]);
chooserResults.add (URL (scheme + "://" + path));
auto pathComponents = StringArray::fromTokens (nsStringToJuce ([urlToAdd path]), "/", {});
for (auto& component : pathComponents)
component = URL::addEscapeChars (component, false);
chooserResults.add (URL (scheme + "://" + pathComponents.joinIntoString ("/")));
};
if (isSave)
@ -218,7 +235,7 @@ private:
else
{
auto* openPanel = (NSOpenPanel*) panel;
auto* urls = [openPanel URLs];
auto urls = [openPanel URLs];
for (unsigned int i = 0; i < [urls count]; ++i)
addURLResult ([urls objectAtIndex: i]);

View File

@ -33,11 +33,11 @@ struct JuceMainMenuBarHolder : private DeletedAtShutdown
JuceMainMenuBarHolder()
: mainMenuBar ([[NSMenu alloc] initWithTitle: nsStringLiteral ("MainMenu")])
{
auto* item = [mainMenuBar addItemWithTitle: nsStringLiteral ("Apple")
action: nil
auto item = [mainMenuBar addItemWithTitle: nsStringLiteral ("Apple")
action: nil
keyEquivalent: nsEmptyString()];
auto* appMenu = [[NSMenu alloc] initWithTitle: nsStringLiteral ("Apple")];
auto appMenu = [[NSMenu alloc] initWithTitle: nsStringLiteral ("Apple")];
[NSApp performSelector: @selector (setAppleMenu:) withObject: appMenu];
[mainMenuBar setSubmenu: appMenu forItem: item];
@ -73,7 +73,7 @@ public:
JuceMenuCallbackClass::setOwner (callback, this);
}
~JuceMainMenuHandler()
~JuceMainMenuHandler() override
{
setMenu (nullptr, nullptr, String());
@ -277,9 +277,9 @@ public:
}
else
{
auto* item = [[NSMenuItem alloc] initWithTitle: text
action: @selector (menuItemInvoked:)
keyEquivalent: nsEmptyString()];
auto item = [[NSMenuItem alloc] initWithTitle: text
action: @selector (menuItemInvoked:)
keyEquivalent: nsEmptyString()];
[item setTag: topLevelIndex];
[item setEnabled: i.isEnabled];
@ -478,9 +478,9 @@ private:
{
if (isPositiveAndBelow (menuItemIndex, (int) [parentMenu numberOfItems]))
{
auto* menuItem = [parentMenu itemAtIndex:menuItemIndex];
auto menuItem = [parentMenu itemAtIndex:menuItemIndex];
if (auto* submenu = [menuItem submenu])
if (auto submenu = [menuItem submenu])
removeItemRecursive (submenu);
[parentMenu removeItem:menuItem];
@ -706,7 +706,7 @@ namespace MainMenuHelpers
{
if ([mainMenu numberOfItems] > 0)
{
if (auto* appMenu = [[mainMenu itemAtIndex:0] submenu])
if (auto appMenu = [[mainMenu itemAtIndex: 0] submenu])
{
[appMenu removeAllItems];
MainMenuHelpers::createStandardAppMenu (appMenu, app->getApplicationName(), extraItems);
@ -765,7 +765,7 @@ const PopupMenu* MenuBarModel::getMacExtraAppleItemsMenu()
return nullptr;
}
typedef void (*MenuTrackingChangedCallback) (bool);
using MenuTrackingChangedCallback = void (*)(bool);
extern MenuTrackingChangedCallback menuTrackingChangedCallback;
static void mainMenuTrackingChanged (bool isTracking)

View File

@ -164,11 +164,6 @@ void MouseCursor::deleteMouseCursor (void* const cursorHandle, const bool /*isSt
[((NSCursor*) cursorHandle) release];
}
void MouseCursor::showInAllWindows() const
{
showInWindow (nullptr);
}
void MouseCursor::showInWindow (ComponentPeer*) const
{
auto c = (NSCursor*) getHandle();
@ -184,7 +179,6 @@ void MouseCursor::showInWindow (ComponentPeer*) const
void* CustomMouseCursorInfo::create() const { return nullptr; }
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType) { return nullptr; }
void MouseCursor::deleteMouseCursor (void*, bool) {}
void MouseCursor::showInAllWindows() const {}
void MouseCursor::showInWindow (ComponentPeer*) const {}
#endif

View File

@ -64,10 +64,6 @@ static NSRect flippedScreenRect (NSRect r) noexcept
return r;
}
#if JUCE_MODULE_AVAILABLE_juce_opengl
void componentPeerAboutToChange (Component&, bool);
#endif
//==============================================================================
class NSViewComponentPeer : public ComponentPeer,
private Timer
@ -75,6 +71,7 @@ class NSViewComponentPeer : public ComponentPeer,
public:
NSViewComponentPeer (Component& comp, const int windowStyleFlags, NSView* viewToAttachTo)
: ComponentPeer (comp, windowStyleFlags),
safeComponent (&comp),
isSharedWindow (viewToAttachTo != nil),
lastRepaintTime (Time::getMillisecondCounter())
{
@ -95,24 +92,6 @@ public:
name: NSViewFrameDidChangeNotification
object: view];
if (! isSharedWindow)
{
[notificationCenter addObserver: view
selector: @selector (frameChanged:)
name: NSWindowDidMoveNotification
object: window];
[notificationCenter addObserver: view
selector: @selector (frameChanged:)
name: NSWindowDidMiniaturizeNotification
object: window];
[notificationCenter addObserver: view
selector: @selector (frameChanged:)
name: NSWindowDidDeminiaturizeNotification
object: window];
}
[view setPostsFrameChangedNotifications: YES];
if (isSharedWindow)
@ -137,7 +116,18 @@ public:
#else
[window setDelegate: window];
#endif
[window setOpaque: component.isOpaque()];
#if defined (MAC_OS_X_VERSION_10_14)
if (! [window isOpaque])
[window setBackgroundColor: [NSColor clearColor]];
#if defined (MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)
[view setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]];
#endif
#endif
[window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)];
if (component.isAlwaysOnTop())
@ -165,8 +155,28 @@ public:
#if defined (MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13)
if ([window respondsToSelector: @selector (setTabbingMode:)])
[window setTabbingMode:NSWindowTabbingModeDisallowed];
[window setTabbingMode: NSWindowTabbingModeDisallowed];
#endif
[notificationCenter addObserver: view
selector: @selector (frameChanged:)
name: NSWindowDidMoveNotification
object: window];
[notificationCenter addObserver: view
selector: @selector (frameChanged:)
name: NSWindowDidMiniaturizeNotification
object: window];
[notificationCenter addObserver: view
selector: @selector (windowWillMiniaturize:)
name: NSWindowWillMiniaturizeNotification
object: window];
[notificationCenter addObserver: view
selector: @selector (windowDidDeminiaturize:)
name: NSWindowDidDeminiaturizeNotification
object: window];
}
auto alpha = component.getAlpha();
@ -187,7 +197,7 @@ public:
};
}
~NSViewComponentPeer()
~NSViewComponentPeer() override
{
[notificationCenter removeObserver: view];
setOwner (view, nullptr);
@ -216,7 +226,10 @@ public:
{
if (isSharedWindow)
{
[view setHidden: ! shouldBeVisible];
if (shouldBeVisible)
[view setHidden: false];
else if ([window firstResponder] != view || ([window firstResponder] == view && [window makeFirstResponder: nil]))
[view setHidden: true];
}
else
{
@ -478,10 +491,14 @@ public:
bool setAlwaysOnTop (bool alwaysOnTop) override
{
if (! isSharedWindow)
{
[window setLevel: alwaysOnTop ? ((getStyleFlags() & windowIsTemporary) != 0 ? NSPopUpMenuWindowLevel
: NSFloatingWindowLevel)
: NSNormalWindowLevel];
isAlwaysOnTop = alwaysOnTop;
}
return true;
}
@ -705,12 +722,11 @@ public:
void redirectWillMoveToWindow (NSWindow* newWindow)
{
#if JUCE_MODULE_AVAILABLE_juce_opengl
if ([view window] == window)
componentPeerAboutToChange (getComponent(), newWindow == nullptr);
#else
ignoreUnused (newWindow);
#endif
if (isSharedWindow && [view window] == window && newWindow == nullptr)
{
if (auto* comp = safeComponent.get())
comp->setVisible (false);
}
}
void sendMouseEvent (NSEvent* ev)
@ -780,7 +796,7 @@ public:
{
// (need to retain this in case a modal loop runs in handleKeyEvent and
// our event object gets lost)
const NSObjectRetainer<NSEvent> r (ev);
const std::unique_ptr<NSEvent, NSObjectDeleter> r ([ev retain]);
updateKeysDown (ev, true);
bool used = handleKeyEvent (ev, true);
@ -810,7 +826,7 @@ public:
void redirectModKeyChange (NSEvent* ev)
{
// (need to retain this in case a modal loop runs and our event object gets lost)
const NSObjectRetainer<NSEvent> r (ev);
const std::unique_ptr<NSEvent, NSObjectDeleter> r ([ev retain]);
keysCurrentlyDown.clear();
handleKeyUpOrDown (true);
@ -1046,7 +1062,15 @@ public:
void viewMovedToWindow()
{
if (isSharedWindow)
window = [view window];
{
auto newWindow = [view window];
bool shouldSetVisible = (window == nullptr && newWindow != nullptr);
window = newWindow;
if (shouldSetVisible)
getComponent().setVisible (true);
}
}
void liveResizingStart()
@ -1314,10 +1338,13 @@ public:
while ((track = [enumerator nextObject]) != nil)
{
NSURL* url = [NSURL URLWithString: [track valueForKey: nsStringLiteral ("Location")]];
if (id value = [track valueForKey: nsStringLiteral ("Location")])
{
NSURL* url = [NSURL URLWithString: value];
if ([url isFileURL])
files.add (nsStringToJuce ([url path]));
if ([url isFileURL])
files.add (nsStringToJuce ([url path]));
}
}
}
}
@ -1382,6 +1409,7 @@ public:
//==============================================================================
NSWindow* window = nil;
NSView* view = nil;
WeakReference<Component> safeComponent;
bool isSharedWindow = false, fullScreen = false;
bool isWindowInKioskMode = false;
#if USE_COREGRAPHICS_RENDERING
@ -1392,6 +1420,7 @@ public:
bool isZooming = false, isFirstLiveResize = false, textWasInserted = false;
bool isStretchingTop = false, isStretchingLeft = false, isStretchingBottom = false, isStretchingRight = false;
bool windowRepresentsFile = false;
bool isAlwaysOnTop = false, wasAlwaysOnTop = false;
String stringBeingComposed;
NSNotificationCenter* notificationCenter = nil;
@ -1561,6 +1590,8 @@ struct JuceNSViewClass : public ObjCClass<NSView>
addMethod (@selector (magnifyWithEvent:), magnify, "v@:@");
addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "c@:@");
addMethod (@selector (frameChanged:), frameChanged, "v@:@");
addMethod (@selector (windowWillMiniaturize:), windowWillMiniaturize, "v@:@");
addMethod (@selector (windowDidDeminiaturize:), windowDidDeminiaturize, "v@:@");
addMethod (@selector (wantsDefaultClipping:), wantsDefaultClipping, "c@:");
addMethod (@selector (worksWhenModal), worksWhenModal, "c@:");
addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow, "v@:");
@ -1656,6 +1687,31 @@ private:
static void frameChanged (id self, SEL, NSNotification*) { if (auto* p = getOwner (self)) p->redirectMovedOrResized(); }
static void viewDidMoveToWindow (id self, SEL) { if (auto* p = getOwner (self)) p->viewMovedToWindow(); }
static void windowWillMiniaturize (id self, SEL, NSNotification*)
{
if (auto* p = getOwner (self))
{
if (p->isAlwaysOnTop)
{
// there is a bug when restoring minimised always on top windows so we need
// to remove this behaviour before minimising and restore it afterwards
p->setAlwaysOnTop (false);
p->wasAlwaysOnTop = true;
}
}
}
static void windowDidDeminiaturize (id self, SEL, NSNotification*)
{
if (auto* p = getOwner (self))
{
if (p->wasAlwaysOnTop)
p->setAlwaysOnTop (true);
p->redirectMovedOrResized();
}
}
static BOOL isOpaque (id self, SEL)
{
auto* owner = getOwner (self);
@ -2102,6 +2158,8 @@ void Desktop::setKioskComponent (Component* kioskComp, bool shouldBeEnabled, boo
{
if (shouldBeEnabled && ! allowMenusAndBars)
[NSApp setPresentationOptions: NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar];
else if (! shouldBeEnabled)
[NSApp setPresentationOptions: NSApplicationPresentationDefault];
[peer->window performSelector: @selector (toggleFullScreen:) withObject: nil];
}

View File

@ -167,7 +167,7 @@ static NSRect getDragRect (NSView* view, NSEvent* event)
static NSView* getNSViewForDragEvent (Component* sourceComp)
{
if (sourceComp == nullptr)
if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource (0))
sourceComp = draggingSource->getComponentUnderMouse();
if (sourceComp != nullptr)
@ -177,14 +177,22 @@ static NSView* getNSViewForDragEvent (Component* sourceComp)
return nil;
}
struct TextDragDataProviderClass : public ObjCClass<NSObject>
struct NSDraggingSourceHelper : public ObjCClass<NSObject<NSDraggingSource>>
{
TextDragDataProviderClass() : ObjCClass<NSObject> ("JUCE_NSTextDragDataProvider_")
NSDraggingSourceHelper() : ObjCClass<NSObject<NSDraggingSource>> ("JUCENSDraggingSourceHelper_")
{
addIvar<std::function<void()>*> ("callback");
addIvar<String*> ("text");
addIvar<NSDragOperation*> ("operation");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (pasteboard:item:provideDataForType:), provideDataForType, "v@:@@@");
addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), sourceOperationMaskForDraggingContext, "c@:@@");
addMethod (@selector (draggingSession:endedAtPoint:operation:), draggingSessionEnded, "v@:@@@");
addProtocol (@protocol (NSPasteboardItemDataProvider));
registerClass();
}
@ -193,10 +201,23 @@ struct TextDragDataProviderClass : public ObjCClass<NSObject>
object_setInstanceVariable (self, "text", new String (text));
}
static void setCompletionCallback (id self, std::function<void()> cb)
{
object_setInstanceVariable (self, "callback", new std::function<void()> (cb));
}
static void setDragOperation (id self, NSDragOperation op)
{
object_setInstanceVariable (self, "operation", new NSDragOperation (op));
}
private:
static void dealloc (id self, SEL)
{
delete getIvar<String*> (self, "text");
delete getIvar<std::function<void()>*> (self, "callback");
delete getIvar<NSDragOperation*> (self, "operation");
sendSuperclassMessage (self, @selector (dealloc));
}
@ -207,9 +228,29 @@ private:
[sender setData: [juceStringToNS (*text) dataUsingEncoding: NSUTF8StringEncoding]
forType: NSPasteboardTypeString];
}
static NSDragOperation sourceOperationMaskForDraggingContext (id self, SEL, NSDraggingSession*, NSDraggingContext)
{
return *getIvar<NSDragOperation*> (self, "operation");
}
static void draggingSessionEnded (id self, SEL, NSDraggingSession*, NSPoint p, NSDragOperation)
{
// Our view doesn't receive a mouse up when the drag ends so we need to generate one here and send it...
if (auto* view = getNSViewForDragEvent (nullptr))
if (auto* cgEvent = CGEventCreateMouseEvent (nullptr, kCGEventLeftMouseUp, CGPointMake (p.x, p.y), kCGMouseButtonLeft))
if (id e = [NSEvent eventWithCGEvent: cgEvent])
[view mouseUp: e];
if (auto* cb = getIvar<std::function<void()>*> (self, "callback"))
cb->operator()();
}
};
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component* sourceComponent)
static NSDraggingSourceHelper draggingSourceHelper;
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component* sourceComponent,
std::function<void()> callback)
{
if (text.isEmpty())
return false;
@ -218,28 +259,33 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Co
{
JUCE_AUTORELEASEPOOL
{
if (auto* event = [[view window] currentEvent])
if (auto event = [[view window] currentEvent])
{
static TextDragDataProviderClass dataProviderClass;
id delegate = [dataProviderClass.createInstance() init];
TextDragDataProviderClass::setText (delegate, text);
id helper = [draggingSourceHelper.createInstance() init];
NSDraggingSourceHelper::setText (helper, text);
NSDraggingSourceHelper::setDragOperation (helper, NSDragOperationCopy);
auto* pasteboardItem = [[NSPasteboardItem new] autorelease];
[pasteboardItem setDataProvider: delegate
if (callback != nullptr)
NSDraggingSourceHelper::setCompletionCallback (helper, callback);
auto pasteboardItem = [[NSPasteboardItem new] autorelease];
[pasteboardItem setDataProvider: helper
forTypes: [NSArray arrayWithObjects: NSPasteboardTypeString, nil]];
auto* dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter: pasteboardItem] autorelease];
auto dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter: pasteboardItem] autorelease];
NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: nsEmptyString()];
[dragItem setDraggingFrame: getDragRect (view, event) contents: image];
auto* draggingSession = [view beginDraggingSessionWithItems: [NSArray arrayWithObject: dragItem]
event: event
source: delegate];
if (auto session = [view beginDraggingSessionWithItems: [NSArray arrayWithObject: dragItem]
event: event
source: helper])
{
session.animatesToStartingPositionsOnCancelOrFail = YES;
session.draggingFormation = NSDraggingFormationNone;
draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
draggingSession.draggingFormation = NSDraggingFormationNone;
return true;
return true;
}
}
}
}
@ -247,24 +293,8 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Co
return false;
}
struct NSDraggingSourceHelper : public ObjCClass<NSObject<NSDraggingSource>>
{
NSDraggingSourceHelper() : ObjCClass<NSObject<NSDraggingSource>> ("JUCENSDraggingSourceHelper_")
{
addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), sourceOperationMaskForDraggingContext, "c@:@@");
registerClass();
}
static NSDragOperation sourceOperationMaskForDraggingContext (id, SEL, NSDraggingSession*, NSDraggingContext)
{
return NSDragOperationCopy;
}
};
static NSDraggingSourceHelper draggingSourceHelper;
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool /*canMoveFiles*/,
Component* sourceComponent)
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles,
Component* sourceComponent, std::function<void()> callback)
{
if (files.isEmpty())
return false;
@ -273,20 +303,20 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi
{
JUCE_AUTORELEASEPOOL
{
if (auto* event = [[view window] currentEvent])
if (auto event = [[view window] currentEvent])
{
auto* dragItems = [[[NSMutableArray alloc] init] autorelease];
auto dragItems = [[[NSMutableArray alloc] init] autorelease];
for (auto& filename : files)
{
auto* nsFilename = juceStringToNS (filename);
auto* fileURL = [NSURL fileURLWithPath: nsFilename];
auto* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter: fileURL];
auto fileURL = [NSURL fileURLWithPath: nsFilename];
auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter: fileURL];
auto eventPos = [event locationInWindow];
auto dragRect = [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
fromView: nil];
auto* dragImage = [[NSWorkspace sharedWorkspace] iconForFile: nsFilename];
auto dragImage = [[NSWorkspace sharedWorkspace] iconForFile: nsFilename];
[dragItem setDraggingFrame: dragRect
contents: dragImage];
@ -294,11 +324,17 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi
[dragItem release];
}
auto* helper = [draggingSourceHelper.createInstance() autorelease];
auto helper = [draggingSourceHelper.createInstance() autorelease];
if (callback != nullptr)
NSDraggingSourceHelper::setCompletionCallback (helper, callback);
NSDraggingSourceHelper::setDragOperation (helper, canMoveFiles ? NSDragOperationMove
: NSDragOperationCopy);
return [view beginDraggingSessionWithItems: dragItems
event: event
source: helper];
source: helper] != nullptr;
}
}
}
@ -428,18 +464,18 @@ struct DisplaySettingsChangeCallback : private DeletedAtShutdown
{
DisplaySettingsChangeCallback()
{
CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallBack, 0);
CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallBack, nullptr);
}
~DisplaySettingsChangeCallback()
{
CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallBack, 0);
CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallBack, nullptr);
clearSingletonInstance();
}
static void displayReconfigurationCallBack (CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*)
{
const_cast<Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
const_cast<Displays&> (Desktop::getInstance().getDisplays()).refresh();
}
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (DisplaySettingsChangeCallback)
@ -455,9 +491,9 @@ static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
return convertToRectInt (r);
}
static Desktop::Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& mainScreenBottom, const float masterScale)
static Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& mainScreenBottom, const float masterScale)
{
Desktop::Displays::Display d;
Displays::Display d;
d.isMain = (mainScreenBottom == 0);
@ -479,7 +515,7 @@ static Desktop::Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& ma
return d;
}
void Desktop::Displays::findDisplays (const float masterScale)
void Displays::findDisplays (const float masterScale)
{
JUCE_AUTORELEASEPOOL
{

View File

@ -241,49 +241,114 @@ namespace DragAndDropHelpers
return hDrop;
}
bool performDragDrop (FORMATETC* const format, STGMEDIUM* const medium, const DWORD whatToDo)
struct DragAndDropJob : public ThreadPoolJob
{
auto source = new JuceDropSource();
auto data = new JuceDataObject (source, format, medium);
DragAndDropJob (FORMATETC f, STGMEDIUM m, DWORD d, std::function<void()> cb)
: ThreadPoolJob ("DragAndDrop"),
format (f), medium (m), whatToDo (d),
completionCallback (cb)
{
}
DWORD effect;
auto res = DoDragDrop (data, source, whatToDo, &effect);
JobStatus runJob() override
{
OleInitialize (0);
data->Release();
source->Release();
auto source = new JuceDropSource();
auto data = new JuceDataObject (source, &format, &medium);
return res == DRAGDROP_S_DROP;
}
DWORD effect;
DoDragDrop (data, source, whatToDo, &effect);
data->Release();
source->Release();
OleUninitialize();
if (completionCallback != nullptr)
MessageManager::callAsync (completionCallback);
return jobHasFinished;
}
FORMATETC format;
STGMEDIUM medium;
DWORD whatToDo;
std::function<void()> completionCallback;
};
class ThreadPoolHolder : private DeletedAtShutdown
{
public:
ThreadPoolHolder() = default;
~ThreadPoolHolder()
{
// Wait forever if there's a job running. The user needs to cancel the transfer
// in the GUI.
pool.removeAllJobs (true, -1);
clearSingletonInstance();
}
JUCE_DECLARE_SINGLETON_SINGLETHREADED (ThreadPoolHolder, false)
// We need to make sure we don't do simultaneous text and file drag and drops,
// so use a pool that can only run a single job.
ThreadPool pool { 1 };
};
JUCE_IMPLEMENT_SINGLETON (ThreadPoolHolder)
}
//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMove, Component*)
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMove,
Component*, std::function<void()> callback)
{
if (files.isEmpty())
return false;
FORMATETC format = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 };
medium.hGlobal = DragAndDropHelpers::createHDrop (files);
return DragAndDropHelpers::performDragDrop (&format, &medium, canMove ? (DWORD) (DROPEFFECT_COPY | DROPEFFECT_MOVE)
: (DWORD) DROPEFFECT_COPY);
auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
pool.addJob (new DragAndDropHelpers::DragAndDropJob (format, medium,
canMove ? (DROPEFFECT_COPY | DROPEFFECT_MOVE) : DROPEFFECT_COPY,
callback),
true);
return true;
}
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component*)
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component*, std::function<void()> callback)
{
if (text.isEmpty())
return false;
FORMATETC format = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 };
auto numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2);
WCHAR* const data = static_cast<WCHAR*> (GlobalLock (medium.hGlobal));
auto* data = static_cast<WCHAR*> (GlobalLock (medium.hGlobal));
text.copyToUTF16 (data, numBytes);
text.copyToUTF16 (data, numBytes + 2);
format.cfFormat = CF_UNICODETEXT;
GlobalUnlock (medium.hGlobal);
return DragAndDropHelpers::performDragDrop (&format, &medium, DROPEFFECT_COPY | DROPEFFECT_MOVE);
auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
pool.addJob (new DragAndDropHelpers::DragAndDropJob (format,
medium,
DROPEFFECT_COPY | DROPEFFECT_MOVE,
callback),
true);
return true;
}
} // namespace juce

View File

@ -120,6 +120,8 @@ public:
EndDialog (hwnd, 0);
}
Component* getCustomComponent() { return customComponent.get(); }
Array<URL> results;
private:
@ -355,38 +357,42 @@ private:
{
nativeDialogRef.set (hdlg);
if (customComponent)
if (customComponent != nullptr)
{
Component::SafePointer<Component> custom (customComponent.get());
Component::SafePointer<Component> safeCustomComponent (customComponent.get());
RECT r, cr;
GetWindowRect (hdlg, &r);
GetClientRect (hdlg, &cr);
RECT dialogScreenRect, dialogClientRect;
GetWindowRect (hdlg, &dialogScreenRect);
GetClientRect (hdlg, &dialogClientRect);
auto componentWidth = custom->getWidth();
auto screenRectangle = Rectangle<int>::leftTopRightBottom (dialogScreenRect.left, dialogScreenRect.top,
dialogScreenRect.right, dialogScreenRect.bottom);
SetWindowPos (hdlg, 0,
r.left, r.top,
componentWidth + jmax (150, (int) (r.right - r.left)),
jmax (150, (int) (r.bottom - r.top)),
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
auto scale = Desktop::getInstance().getDisplays().findDisplayForRect (screenRectangle, true).scale;
auto physicalComponentWidth = roundToInt (safeCustomComponent->getWidth() * scale);
SetWindowPos (hdlg, 0, screenRectangle.getX(), screenRectangle.getY(),
physicalComponentWidth + jmax (150, screenRectangle.getWidth()),
jmax (150, screenRectangle.getHeight()),
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
auto appendCustomComponent = [safeCustomComponent, dialogClientRect, scale, hdlg]() mutable
{
if (safeCustomComponent != nullptr)
{
auto scaledClientRectangle = Rectangle<int>::leftTopRightBottom (dialogClientRect.left, dialogClientRect.top,
dialogClientRect.right, dialogClientRect.bottom) / scale;
safeCustomComponent->setBounds (scaledClientRectangle.getRight(), scaledClientRectangle.getY(),
safeCustomComponent->getWidth(), scaledClientRectangle.getHeight());
safeCustomComponent->addToDesktop (0, hdlg);
}
};
if (MessageManager::getInstance()->isThisTheMessageThread())
{
custom->setBounds (cr.right, cr.top, componentWidth, cr.bottom - cr.top);
custom->addToDesktop (0, hdlg);
}
appendCustomComponent();
else
{
MessageManager::callAsync ([custom, cr, componentWidth, hdlg]() mutable
{
if (custom != nullptr)
{
custom->setBounds (cr.right, cr.top, componentWidth, cr.bottom - cr.top);
custom->addToDesktop (0, hdlg);
}
});
}
MessageManager::callAsync (appendCustomComponent);
}
}
}
@ -397,6 +403,11 @@ private:
getNativeDialogList().remove (hdlg);
nativeDialogRef.set (nullptr);
if (MessageManager::getInstance()->isThisTheMessageThread())
customComponent = nullptr;
else
MessageManager::callAsync ([this] { customComponent = nullptr; });
}
void selectionChanged (HWND hdlg)
@ -553,6 +564,17 @@ public:
owner.finished (nativeFileChooser->results);
}
bool canModalEventBeSentToComponent (const Component* targetComponent) override
{
if (targetComponent == nullptr)
return false;
if (targetComponent == nativeFileChooser->getCustomComponent())
return true;
return targetComponent->findParentComponentOfClass<FilePreviewComponent>() != nullptr;
}
private:
FileChooser& owner;
Win32NativeFileChooser::Ptr nativeFileChooser;

File diff suppressed because it is too large Load Diff