- clean working copy for leaving SVN
This commit is contained in:
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
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.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
package com.juce;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.graphics.*;
|
||||
import android.opengl.*;
|
||||
import android.text.ClipboardManager;
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||
|
||||
//==============================================================================
|
||||
public final class JuceAppActivity extends Activity
|
||||
{
|
||||
//==============================================================================
|
||||
static
|
||||
{
|
||||
System.loadLibrary ("juce_jni");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreate (Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate (savedInstanceState);
|
||||
|
||||
viewHolder = new ViewHolder (this);
|
||||
setContentView (viewHolder);
|
||||
|
||||
setVolumeControlStream (AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onDestroy()
|
||||
{
|
||||
quitApp();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onPause()
|
||||
{
|
||||
if (viewHolder != null)
|
||||
viewHolder.onPause();
|
||||
|
||||
suspendApp();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
if (viewHolder != null)
|
||||
viewHolder.onResume();
|
||||
|
||||
resumeApp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged (Configuration cfg)
|
||||
{
|
||||
super.onConfigurationChanged (cfg);
|
||||
setContentView (viewHolder);
|
||||
}
|
||||
|
||||
private void callAppLauncher()
|
||||
{
|
||||
launchApp (getApplicationInfo().publicSourceDir,
|
||||
getApplicationInfo().dataDir);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void launchApp (String appFile, String appDataDir);
|
||||
private native void quitApp();
|
||||
private native void suspendApp();
|
||||
private native void resumeApp();
|
||||
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
|
||||
|
||||
//==============================================================================
|
||||
public native void deliverMessage (long value);
|
||||
private android.os.Handler messageHandler = new android.os.Handler();
|
||||
|
||||
public final void postMessage (long value)
|
||||
{
|
||||
messageHandler.post (new MessageCallback (value));
|
||||
}
|
||||
|
||||
private final class MessageCallback implements Runnable
|
||||
{
|
||||
public MessageCallback (long value_) { value = value_; }
|
||||
public final void run() { deliverMessage (value); }
|
||||
|
||||
private long value;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private ViewHolder viewHolder;
|
||||
|
||||
public final ComponentPeerView createNewView (boolean opaque, long host)
|
||||
{
|
||||
ComponentPeerView v = new ComponentPeerView (this, opaque, host);
|
||||
viewHolder.addView (v);
|
||||
return v;
|
||||
}
|
||||
|
||||
public final void deleteView (ComponentPeerView view)
|
||||
{
|
||||
ViewGroup group = (ViewGroup) (view.getParent());
|
||||
|
||||
if (group != null)
|
||||
group.removeView (view);
|
||||
}
|
||||
|
||||
final class ViewHolder extends ViewGroup
|
||||
{
|
||||
public ViewHolder (Context context)
|
||||
{
|
||||
super (context);
|
||||
setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
|
||||
setFocusable (false);
|
||||
}
|
||||
|
||||
protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||
{
|
||||
setScreenSize (getWidth(), getHeight(), getDPI());
|
||||
|
||||
if (isFirstResize)
|
||||
{
|
||||
isFirstResize = false;
|
||||
callAppLauncher();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onPause()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof ComponentPeerView)
|
||||
((ComponentPeerView) v).onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onResume()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof ComponentPeerView)
|
||||
((ComponentPeerView) v).onResume();
|
||||
}
|
||||
}
|
||||
|
||||
private final int getDPI()
|
||||
{
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics (metrics);
|
||||
return metrics.densityDpi;
|
||||
}
|
||||
|
||||
private boolean isFirstResize = true;
|
||||
}
|
||||
|
||||
public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
|
||||
{
|
||||
canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final String getClipboardContent()
|
||||
{
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||
return clipboard.getText().toString();
|
||||
}
|
||||
|
||||
public final void setClipboardContent (String newText)
|
||||
{
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||
clipboard.setText (newText);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final void showMessageBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public final void showOkCancelBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public final void showYesNoCancelBox (String title, String message, final long callback)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||
builder.setTitle (title)
|
||||
.setMessage (message)
|
||||
.setCancelable (true)
|
||||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton ("No", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 2);
|
||||
}
|
||||
})
|
||||
.setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick (DialogInterface dialog, int id)
|
||||
{
|
||||
dialog.cancel();
|
||||
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public native void alertDismissed (long callback, int id);
|
||||
|
||||
//==============================================================================
|
||||
public final class ComponentPeerView extends ViewGroup
|
||||
implements View.OnFocusChangeListener
|
||||
{
|
||||
public ComponentPeerView (Context context, boolean opaque_, long host)
|
||||
{
|
||||
super (context);
|
||||
this.host = host;
|
||||
setWillNotDraw (false);
|
||||
opaque = opaque_;
|
||||
|
||||
setFocusable (true);
|
||||
setFocusableInTouchMode (true);
|
||||
setOnFocusChangeListener (this);
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void handlePaint (long host, Canvas canvas);
|
||||
|
||||
@Override
|
||||
public void onDraw (Canvas canvas)
|
||||
{
|
||||
handlePaint (host, canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque()
|
||||
{
|
||||
return opaque;
|
||||
}
|
||||
|
||||
private boolean opaque;
|
||||
private long host;
|
||||
|
||||
//==============================================================================
|
||||
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)
|
||||
{
|
||||
int action = event.getAction();
|
||||
long time = event.getEventTime();
|
||||
|
||||
switch (action & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
int n = event.getPointerCount();
|
||||
for (int i = 0; i < n; ++i)
|
||||
handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), 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);
|
||||
|
||||
public void showKeyboard (String type)
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager) 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown (int keyCode, KeyEvent event)
|
||||
{
|
||||
switch (keyCode)
|
||||
{
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
return super.onKeyDown (keyCode, event);
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
handleKeyDown (host, keyCode, event.getUnicodeChar());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp (int keyCode, KeyEvent event)
|
||||
{
|
||||
handleKeyUp (host, keyCode, event.getUnicodeChar());
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
viewSizeChanged (host);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
requestTransparentRegion (getChildAt (i));
|
||||
}
|
||||
|
||||
private native void viewSizeChanged (long host);
|
||||
|
||||
@Override
|
||||
public void onFocusChange (View v, boolean hasFocus)
|
||||
{
|
||||
if (v == this)
|
||||
focusChanged (host, hasFocus);
|
||||
}
|
||||
|
||||
private native void focusChanged (long host, boolean hasFocus);
|
||||
|
||||
public void setViewName (String newName) {}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
public final void onPause()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof OpenGLView)
|
||||
((OpenGLView) v).onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public final void onResume()
|
||||
{
|
||||
for (int i = getChildCount(); --i >= 0;)
|
||||
{
|
||||
View v = getChildAt (i);
|
||||
|
||||
if (v instanceof OpenGLView)
|
||||
((OpenGLView) v).onResume();
|
||||
}
|
||||
}
|
||||
|
||||
public OpenGLView createGLView()
|
||||
{
|
||||
OpenGLView glView = new OpenGLView (getContext());
|
||||
addView (glView);
|
||||
return glView;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final class OpenGLView extends GLSurfaceView
|
||||
implements GLSurfaceView.Renderer
|
||||
{
|
||||
OpenGLView (Context context)
|
||||
{
|
||||
super (context);
|
||||
setEGLContextClientVersion (2);
|
||||
setRenderer (this);
|
||||
setRenderMode (RENDERMODE_WHEN_DIRTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated (GL10 unused, EGLConfig config)
|
||||
{
|
||||
contextCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged (GL10 unused, int width, int height)
|
||||
{
|
||||
contextChangedSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame (GL10 unused)
|
||||
{
|
||||
render();
|
||||
}
|
||||
|
||||
private native void contextCreated();
|
||||
private native void contextChangedSize();
|
||||
private native void render();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
|
||||
{
|
||||
Path p = new Path();
|
||||
paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
|
||||
|
||||
RectF boundsF = new RectF();
|
||||
p.computeBounds (boundsF, true);
|
||||
matrix.mapRect (boundsF);
|
||||
|
||||
boundsF.roundOut (bounds);
|
||||
bounds.left--;
|
||||
bounds.right++;
|
||||
|
||||
final int w = bounds.width();
|
||||
final int h = Math.max (1, bounds.height());
|
||||
|
||||
Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas c = new Canvas (bm);
|
||||
matrix.postTranslate (-bounds.left, -bounds.top);
|
||||
c.setMatrix (matrix);
|
||||
c.drawPath (p, paint);
|
||||
|
||||
final int sizeNeeded = w * h;
|
||||
if (cachedRenderArray.length < sizeNeeded)
|
||||
cachedRenderArray = new int [sizeNeeded];
|
||||
|
||||
bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
|
||||
bm.recycle();
|
||||
return cachedRenderArray;
|
||||
}
|
||||
|
||||
private int[] cachedRenderArray = new int [256];
|
||||
|
||||
//==============================================================================
|
||||
public static class HTTPStream
|
||||
{
|
||||
public HTTPStream (HttpURLConnection connection_,
|
||||
int[] statusCode, StringBuffer responseHeaders) throws IOException
|
||||
{
|
||||
connection = connection_;
|
||||
|
||||
try
|
||||
{
|
||||
inputStream = new BufferedInputStream (connection.getInputStream());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (connection.getResponseCode() < org.apache.http.HttpStatus.SC_BAD_REQUEST)
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
statusCode[0] = connection.getResponseCode();
|
||||
}
|
||||
|
||||
if (statusCode[0] >= org.apache.http.HttpStatus.SC_BAD_REQUEST)
|
||||
inputStream = connection.getErrorStream();
|
||||
else
|
||||
inputStream = connection.getInputStream();
|
||||
|
||||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
|
||||
if (entry.getKey() != null && entry.getValue() != null)
|
||||
responseHeaders.append (entry.getKey() + ": "
|
||||
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
|
||||
}
|
||||
|
||||
public final void release()
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
public final int read (byte[] buffer, int numBytes)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
try
|
||||
{
|
||||
num = inputStream.read (buffer, 0, numBytes);
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
if (num > 0)
|
||||
position += num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public final long getPosition() { return position; }
|
||||
public final long getTotalLength() { return -1; }
|
||||
public final boolean isExhausted() { return false; }
|
||||
public final boolean setPosition (long newPos) { return false; }
|
||||
|
||||
private HttpURLConnection connection;
|
||||
private InputStream inputStream;
|
||||
private long position;
|
||||
}
|
||||
|
||||
public static final HTTPStream createHTTPStream (String address,
|
||||
boolean isPost, byte[] postData, String headers,
|
||||
int timeOutMs, int[] statusCode,
|
||||
StringBuffer responseHeaders)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpURLConnection connection = (HttpURLConnection) (new URL(address)
|
||||
.openConnection());
|
||||
if (connection != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isPost)
|
||||
{
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setConnectTimeout(timeOutMs);
|
||||
connection.setDoOutput(true);
|
||||
connection.setChunkedStreamingMode(0);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
out.write(postData);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
return new HTTPStream (connection, statusCode, responseHeaders);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void launchURL (String url)
|
||||
{
|
||||
startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
|
||||
}
|
||||
|
||||
public static final String getLocaleValue (boolean isRegion)
|
||||
{
|
||||
java.util.Locale locale = java.util.Locale.getDefault();
|
||||
|
||||
return isRegion ? locale.getDisplayCountry (java.util.Locale.US)
|
||||
: locale.getDisplayLanguage (java.util.Locale.US);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private final class SingleMediaScanner implements MediaScannerConnectionClient
|
||||
{
|
||||
public SingleMediaScanner (Context context, String filename)
|
||||
{
|
||||
file = filename;
|
||||
msc = new MediaScannerConnection (context, this);
|
||||
msc.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaScannerConnected()
|
||||
{
|
||||
msc.scanFile (file, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanCompleted (String path, Uri uri)
|
||||
{
|
||||
msc.disconnect();
|
||||
}
|
||||
|
||||
private MediaScannerConnection msc;
|
||||
private String file;
|
||||
}
|
||||
|
||||
public final void scanFile (String filename)
|
||||
{
|
||||
new SingleMediaScanner (this, filename);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||
#define JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||
|
||||
#include "../system/juce_TargetPlatform.h"
|
||||
#undef T
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
|
||||
#if JUCE_IOS
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#define Point CarbonDummyPointName
|
||||
#define Component CarbonDummyCompName
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreAudio/HostTime.h>
|
||||
#undef Point
|
||||
#undef Component
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fnmatch.h>
|
||||
#include <utime.h>
|
||||
#include <dlfcn.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/message.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
#if JUCE_MSVC
|
||||
#ifndef _CPPRTTI
|
||||
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4100 4201 4514 4312 4995)
|
||||
#endif
|
||||
|
||||
#define STRICT 1
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#if JUCE_MINGW
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <tchar.h>
|
||||
#include <stddef.h>
|
||||
#include <ctime>
|
||||
#include <wininet.h>
|
||||
#include <nb30.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mapi.h>
|
||||
#include <float.h>
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#if JUCE_MINGW
|
||||
#include <basetyps.h>
|
||||
#else
|
||||
#include <crtdbg.h>
|
||||
#include <comutil.h>
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
|
||||
#endif
|
||||
|
||||
#if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "kernel32.lib")
|
||||
#pragma comment (lib, "user32.lib")
|
||||
#pragma comment (lib, "wininet.lib")
|
||||
#pragma comment (lib, "advapi32.lib")
|
||||
#pragma comment (lib, "ws2_32.lib")
|
||||
#pragma comment (lib, "version.lib")
|
||||
#pragma comment (lib, "shlwapi.lib")
|
||||
#pragma comment (lib, "winmm.lib")
|
||||
|
||||
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppwd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsuppw.lib")
|
||||
#endif
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsupp.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||
|
||||
dll: the DynamicLibrary object
|
||||
functionName: function to import
|
||||
localFunctionName: name you want to use to actually call it (must be different)
|
||||
returnType: the return type
|
||||
params: list of params (bracketed)
|
||||
*/
|
||||
#define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_LINUX
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fnmatch.h>
|
||||
#include <utime.h>
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_ANDROID
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pwd.h>
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
// Need to clear various moronic redefinitions made by system headers..
|
||||
#undef max
|
||||
#undef min
|
||||
#undef direct
|
||||
#undef check
|
||||
|
||||
#endif // JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String File::getVersion() const
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
case userDocumentsDirectory:
|
||||
case userMusicDirectory:
|
||||
case userMoviesDirectory:
|
||||
case userPicturesDirectory:
|
||||
case userApplicationDataDirectory:
|
||||
case userDesktopDirectory:
|
||||
return File (android.appDataDir);
|
||||
|
||||
case commonApplicationDataDirectory:
|
||||
case commonDocumentsDirectory:
|
||||
return File (android.appDataDir);
|
||||
|
||||
case globalApplicationsDirectory:
|
||||
return File ("/system/app");
|
||||
|
||||
case tempDirectory:
|
||||
return File (android.appDataDir).getChildFile (".temp");
|
||||
|
||||
case invokedExecutableFile:
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
case hostApplicationPath:
|
||||
return juce_getExecutableFile();
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return File();
|
||||
}
|
||||
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
const LocalRef<jstring> t (javaString (fileName));
|
||||
android.activity.callVoidMethod (JuceAppActivity.launchURL, t.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||
#define JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||
|
||||
#if ! (defined (JUCE_ANDROID_ACTIVITY_CLASSNAME) && defined (JUCE_ANDROID_ACTIVITY_CLASSPATH))
|
||||
#error "The JUCE_ANDROID_ACTIVITY_CLASSNAME and JUCE_ANDROID_ACTIVITY_CLASSPATH macros must be set!"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
extern JNIEnv* getEnv() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
class GlobalRef
|
||||
{
|
||||
public:
|
||||
inline GlobalRef() noexcept : obj (0) {}
|
||||
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
|
||||
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
|
||||
~GlobalRef() { clear(); }
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
if (obj != 0)
|
||||
{
|
||||
getEnv()->DeleteGlobalRef (obj);
|
||||
obj = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline GlobalRef& operator= (const GlobalRef& other)
|
||||
{
|
||||
jobject newObj = retain (other.obj);
|
||||
clear();
|
||||
obj = newObj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline operator jobject() const noexcept { return obj; }
|
||||
inline jobject get() const noexcept { return obj; }
|
||||
|
||||
//==============================================================================
|
||||
#define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \
|
||||
returnType call##typeName##Method (jmethodID methodID, ... ) const \
|
||||
{ \
|
||||
va_list args; \
|
||||
va_start (args, methodID); \
|
||||
returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \
|
||||
va_end (args); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
DECLARE_CALL_TYPE_METHOD (jobject, Object)
|
||||
DECLARE_CALL_TYPE_METHOD (jboolean, Boolean)
|
||||
DECLARE_CALL_TYPE_METHOD (jbyte, Byte)
|
||||
DECLARE_CALL_TYPE_METHOD (jchar, Char)
|
||||
DECLARE_CALL_TYPE_METHOD (jshort, Short)
|
||||
DECLARE_CALL_TYPE_METHOD (jint, Int)
|
||||
DECLARE_CALL_TYPE_METHOD (jlong, Long)
|
||||
DECLARE_CALL_TYPE_METHOD (jfloat, Float)
|
||||
DECLARE_CALL_TYPE_METHOD (jdouble, Double)
|
||||
#undef DECLARE_CALL_TYPE_METHOD
|
||||
|
||||
void callVoidMethod (jmethodID methodID, ... ) const
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, methodID);
|
||||
getEnv()->CallVoidMethodV (obj, methodID, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
jobject obj;
|
||||
|
||||
static inline jobject retain (jobject obj)
|
||||
{
|
||||
return obj == 0 ? 0 : getEnv()->NewGlobalRef (obj);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename JavaType>
|
||||
class LocalRef
|
||||
{
|
||||
public:
|
||||
explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
|
||||
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
|
||||
~LocalRef() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (obj != 0)
|
||||
getEnv()->DeleteLocalRef (obj);
|
||||
}
|
||||
|
||||
LocalRef& operator= (const LocalRef& other)
|
||||
{
|
||||
jobject newObj = retain (other.obj);
|
||||
clear();
|
||||
obj = newObj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator JavaType() const noexcept { return obj; }
|
||||
inline JavaType get() const noexcept { return obj; }
|
||||
|
||||
private:
|
||||
JavaType obj;
|
||||
|
||||
static JavaType retain (JavaType obj)
|
||||
{
|
||||
return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
String juceString (JNIEnv* env, jstring s)
|
||||
{
|
||||
const char* const utf8 = env->GetStringUTFChars (s, nullptr);
|
||||
CharPointer_UTF8 utf8CP (utf8);
|
||||
const String result (utf8CP);
|
||||
env->ReleaseStringUTFChars (s, utf8);
|
||||
return result;
|
||||
}
|
||||
|
||||
String juceString (jstring s)
|
||||
{
|
||||
return juceString (getEnv(), s);
|
||||
}
|
||||
|
||||
LocalRef<jstring> javaString (const String& s)
|
||||
{
|
||||
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
|
||||
}
|
||||
|
||||
LocalRef<jstring> javaStringFromChar (const juce_wchar c)
|
||||
{
|
||||
char utf8[8] = { 0 };
|
||||
CharPointer_UTF8 (utf8).write (c);
|
||||
return LocalRef<jstring> (getEnv()->NewStringUTF (utf8));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JNIClassBase
|
||||
{
|
||||
public:
|
||||
explicit JNIClassBase (const char* classPath);
|
||||
virtual ~JNIClassBase();
|
||||
|
||||
inline operator jclass() const noexcept { return classRef; }
|
||||
|
||||
static void initialiseAllClasses (JNIEnv*);
|
||||
static void releaseAllClasses (JNIEnv*);
|
||||
|
||||
protected:
|
||||
virtual void initialiseFields (JNIEnv*) = 0;
|
||||
|
||||
jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params);
|
||||
jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params);
|
||||
jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature);
|
||||
jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature);
|
||||
|
||||
private:
|
||||
const char* const classPath;
|
||||
jclass classRef;
|
||||
|
||||
static Array<JNIClassBase*>& getClasses();
|
||||
void initialise (JNIEnv*);
|
||||
void release (JNIEnv*);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (JNIClassBase)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params);
|
||||
#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params);
|
||||
#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature);
|
||||
#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature) fieldID = resolveStaticField (env, stringName, signature);
|
||||
#define DECLARE_JNI_METHOD(methodID, stringName, params) jmethodID methodID;
|
||||
#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID;
|
||||
|
||||
#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
|
||||
class CppClassName ## _Class : public JNIClassBase \
|
||||
{ \
|
||||
public: \
|
||||
CppClassName ## _Class() : JNIClassBase (javaPath) {} \
|
||||
\
|
||||
void initialiseFields (JNIEnv* env) \
|
||||
{ \
|
||||
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \
|
||||
} \
|
||||
\
|
||||
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \
|
||||
}; \
|
||||
static CppClassName ## _Class CppClassName;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \
|
||||
extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params
|
||||
|
||||
//==============================================================================
|
||||
class AndroidSystem
|
||||
{
|
||||
public:
|
||||
AndroidSystem();
|
||||
|
||||
void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir);
|
||||
void shutdown (JNIEnv*);
|
||||
|
||||
//==============================================================================
|
||||
GlobalRef activity;
|
||||
String appFile, appDataDir;
|
||||
int screenWidth, screenHeight, dpi;
|
||||
};
|
||||
|
||||
extern AndroidSystem android;
|
||||
|
||||
//==============================================================================
|
||||
class ThreadLocalJNIEnvHolder
|
||||
{
|
||||
public:
|
||||
ThreadLocalJNIEnvHolder() noexcept
|
||||
: jvm (nullptr)
|
||||
{
|
||||
zeromem (threads, sizeof (threads));
|
||||
zeromem (envs, sizeof (envs));
|
||||
}
|
||||
|
||||
void initialise (JNIEnv* env)
|
||||
{
|
||||
// NB: the DLL can be left loaded by the JVM, so the same static
|
||||
// objects can end up being reused by subsequent runs of the app
|
||||
zeromem (threads, sizeof (threads));
|
||||
zeromem (envs, sizeof (envs));
|
||||
|
||||
env->GetJavaVM (&jvm);
|
||||
addEnv (env);
|
||||
}
|
||||
|
||||
JNIEnv* attach() noexcept
|
||||
{
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
return addEnv (env);
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* getOrAttach() noexcept
|
||||
{
|
||||
if (JNIEnv* env = get())
|
||||
return env;
|
||||
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
|
||||
if (JNIEnv* env = get())
|
||||
return env;
|
||||
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
return addEnv (env);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
JavaVM* jvm;
|
||||
enum { maxThreads = 32 };
|
||||
pthread_t threads [maxThreads];
|
||||
JNIEnv* envs [maxThreads];
|
||||
SpinLock addRemoveLock;
|
||||
|
||||
JNIEnv* addEnv (JNIEnv* env) noexcept
|
||||
{
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
{
|
||||
if (threads[i] == 0)
|
||||
{
|
||||
envs[i] = env;
|
||||
threads[i] = thisThread;
|
||||
return env;
|
||||
}
|
||||
}
|
||||
|
||||
jassertfalse; // too many threads!
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv* get() const noexcept
|
||||
{
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
return envs[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv* attachToCurrentThread()
|
||||
{
|
||||
JNIEnv* env = nullptr;
|
||||
jvm->AttachCurrentThread (&env, nullptr);
|
||||
return env;
|
||||
}
|
||||
};
|
||||
|
||||
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
struct AndroidThreadScope
|
||||
{
|
||||
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
|
||||
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
|
||||
METHOD (deleteView, "deleteView", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
|
||||
METHOD (postMessage, "postMessage", "(J)V") \
|
||||
METHOD (finish, "finish", "()V") \
|
||||
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
|
||||
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
|
||||
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
|
||||
METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
|
||||
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
|
||||
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
|
||||
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
|
||||
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V")
|
||||
|
||||
DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH);
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "(I)V") \
|
||||
METHOD (setColor, "setColor", "(I)V") \
|
||||
METHOD (setAlpha, "setAlpha", "(I)V") \
|
||||
METHOD (setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \
|
||||
METHOD (ascent, "ascent", "()F") \
|
||||
METHOD (descent, "descent", "()F") \
|
||||
METHOD (setTextSize, "setTextSize", "(F)V") \
|
||||
METHOD (getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \
|
||||
METHOD (setTextScaleX, "setTextScaleX", "(F)V") \
|
||||
METHOD (getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \
|
||||
METHOD (setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \
|
||||
|
||||
DECLARE_JNI_CLASS (Paint, "android/graphics/Paint");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (setValues, "setValues", "([F)V") \
|
||||
|
||||
DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "(IIII)V") \
|
||||
FIELD (left, "left", "I") \
|
||||
FIELD (right, "right", "I") \
|
||||
FIELD (top, "top", "I") \
|
||||
FIELD (bottom, "bottom", "I") \
|
||||
|
||||
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#endif // JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
__android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", text.toUTF8().getAddress());
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (toString, "toString", "()Ljava/lang/String;") \
|
||||
|
||||
DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (release, "release", "()V") \
|
||||
METHOD (read, "read", "([BI)I") \
|
||||
METHOD (getPosition, "getPosition", "()J") \
|
||||
METHOD (getTotalLength, "getTotalLength", "()J") \
|
||||
METHOD (isExhausted, "isExhausted", "()Z") \
|
||||
METHOD (setPosition, "setPosition", "(J)Z") \
|
||||
|
||||
DECLARE_JNI_CLASS (HTTPStream, JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (String address, bool isPost, const MemoryBlock& postData,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
|
||||
: statusCode (0)
|
||||
{
|
||||
if (! address.contains ("://"))
|
||||
address = "http://" + address;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
jbyteArray postDataArray = 0;
|
||||
|
||||
if (postData.getSize() > 0)
|
||||
{
|
||||
postDataArray = env->NewByteArray (postData.getSize());
|
||||
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
|
||||
}
|
||||
|
||||
LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
|
||||
|
||||
// Annoyingly, the android HTTP functions will choke on this call if you try to do it on the message
|
||||
// thread. You'll need to move your networking code to a background thread to keep it happy..
|
||||
jassert (Thread::getCurrentThread() != nullptr);
|
||||
|
||||
jintArray statusCodeArray = env->NewIntArray (1);
|
||||
jassert (statusCodeArray != 0);
|
||||
|
||||
stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity,
|
||||
JuceAppActivity.createHTTPStream,
|
||||
javaString (address).get(),
|
||||
(jboolean) isPost,
|
||||
postDataArray,
|
||||
javaString (headers).get(),
|
||||
(jint) timeOutMs,
|
||||
statusCodeArray,
|
||||
responseHeaderBuffer.get()));
|
||||
|
||||
jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0);
|
||||
statusCode = statusCodeElements[0];
|
||||
env->ReleaseIntArrayElements (statusCodeArray, statusCodeElements, 0);
|
||||
env->DeleteLocalRef (statusCodeArray);
|
||||
|
||||
if (postDataArray != 0)
|
||||
env->DeleteLocalRef (postDataArray);
|
||||
|
||||
if (stream != 0)
|
||||
{
|
||||
StringArray headerLines;
|
||||
|
||||
{
|
||||
LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
|
||||
StringBuffer.toString));
|
||||
headerLines.addLines (juceString (env, headersString));
|
||||
}
|
||||
|
||||
if (responseHeaders != 0)
|
||||
{
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String& header = headerLines[i];
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
if (stream != 0)
|
||||
stream.callVoidMethod (HTTPStream.release);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return stream == nullptr; }
|
||||
|
||||
bool isExhausted() override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
|
||||
int64 getTotalLength() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
|
||||
int64 getPosition() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
|
||||
bool setPosition (int64 wantedPos) override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
|
||||
|
||||
int read (void* buffer, int bytesToRead) override
|
||||
{
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (stream == nullptr)
|
||||
return 0;
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
jbyteArray javaArray = env->NewByteArray (bytesToRead);
|
||||
|
||||
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||
|
||||
if (numBytes > 0)
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast<jbyte*> (buffer));
|
||||
|
||||
env->DeleteLocalRef (javaArray);
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
GlobalRef stream;
|
||||
int statusCode;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0)
|
||||
{
|
||||
getClasses().add (this);
|
||||
}
|
||||
|
||||
JNIClassBase::~JNIClassBase()
|
||||
{
|
||||
getClasses().removeFirstMatchingValue (this);
|
||||
}
|
||||
|
||||
Array<JNIClassBase*>& JNIClassBase::getClasses()
|
||||
{
|
||||
static Array<JNIClassBase*> classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
void JNIClassBase::initialise (JNIEnv* env)
|
||||
{
|
||||
classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath));
|
||||
jassert (classRef != 0);
|
||||
|
||||
initialiseFields (env);
|
||||
}
|
||||
|
||||
void JNIClassBase::release (JNIEnv* env)
|
||||
{
|
||||
env->DeleteGlobalRef (classRef);
|
||||
}
|
||||
|
||||
void JNIClassBase::initialiseAllClasses (JNIEnv* env)
|
||||
{
|
||||
const Array<JNIClassBase*>& classes = getClasses();
|
||||
for (int i = classes.size(); --i >= 0;)
|
||||
classes.getUnchecked(i)->initialise (env);
|
||||
}
|
||||
|
||||
void JNIClassBase::releaseAllClasses (JNIEnv* env)
|
||||
{
|
||||
const Array<JNIClassBase*>& classes = getClasses();
|
||||
for (int i = classes.size(); --i >= 0;)
|
||||
classes.getUnchecked(i)->release (env);
|
||||
}
|
||||
|
||||
jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||
{
|
||||
jmethodID m = env->GetMethodID (classRef, methodName, params);
|
||||
jassert (m != 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||
{
|
||||
jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
|
||||
jassert (m != 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||
{
|
||||
jfieldID f = env->GetFieldID (classRef, fieldName, signature);
|
||||
jassert (f != 0);
|
||||
return f;
|
||||
}
|
||||
|
||||
jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||
{
|
||||
jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
|
||||
jassert (f != 0);
|
||||
return f;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
static bool systemInitialised = false;
|
||||
#endif
|
||||
|
||||
JNIEnv* getEnv() noexcept
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
if (! systemInitialised)
|
||||
{
|
||||
DBG ("*** Call to getEnv() when system not initialised");
|
||||
jassertfalse;
|
||||
std::exit (EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return threadLocalJNIEnvHolder.getOrAttach();
|
||||
}
|
||||
|
||||
extern "C" jint JNI_OnLoad (JavaVM*, void*)
|
||||
{
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0), dpi (160)
|
||||
{
|
||||
}
|
||||
|
||||
void AndroidSystem::initialise (JNIEnv* env, jobject act, jstring file, jstring dataDir)
|
||||
{
|
||||
screenWidth = screenHeight = 0;
|
||||
dpi = 160;
|
||||
JNIClassBase::initialiseAllClasses (env);
|
||||
|
||||
threadLocalJNIEnvHolder.initialise (env);
|
||||
#if JUCE_DEBUG
|
||||
systemInitialised = true;
|
||||
#endif
|
||||
|
||||
activity = GlobalRef (act);
|
||||
appFile = juceString (env, file);
|
||||
appDataDir = juceString (env, dataDir);
|
||||
}
|
||||
|
||||
void AndroidSystem::shutdown (JNIEnv* env)
|
||||
{
|
||||
activity.clear();
|
||||
|
||||
#if JUCE_DEBUG
|
||||
systemInitialised = false;
|
||||
#endif
|
||||
|
||||
JNIClassBase::releaseAllClasses (env);
|
||||
}
|
||||
|
||||
AndroidSystem android;
|
||||
|
||||
//==============================================================================
|
||||
namespace AndroidStatsHelpers
|
||||
{
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (SystemClass, "java/lang/System");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
String getSystemProperty (const String& name)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||
SystemClass.getProperty,
|
||||
javaString (name).get())));
|
||||
}
|
||||
|
||||
String getLocaleValue (bool isRegion)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (JuceAppActivity,
|
||||
JuceAppActivity.getLocaleValue,
|
||||
isRegion)));
|
||||
}
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD)
|
||||
DECLARE_JNI_CLASS (BuildClass, "android/os/Build");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
String getAndroidOsBuildValue (const char* fieldName)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
|
||||
BuildClass, getEnv()->GetStaticFieldID (BuildClass, fieldName, "Ljava/lang/String;"))));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Android;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
|
||||
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if __ANDROID_API__ >= 9
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (const char* user = getenv ("USER"))
|
||||
return CharPointer_UTF8 (user);
|
||||
|
||||
if (struct passwd* const pw = getpwuid (getuid()))
|
||||
return CharPointer_UTF8 (pw->pw_name);
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
|
||||
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
numCpus = jmax (1, (int) sysconf (_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
// TODO
|
||||
|
||||
struct sched_param param;
|
||||
int policy, maxp, minp;
|
||||
|
||||
const int p = (int) prior;
|
||||
|
||||
if (p <= 1)
|
||||
policy = SCHED_OTHER;
|
||||
else
|
||||
policy = SCHED_RR;
|
||||
|
||||
minp = sched_get_priority_min (policy);
|
||||
maxp = sched_get_priority_max (policy);
|
||||
|
||||
if (p < 2)
|
||||
param.sched_priority = 0;
|
||||
else if (p == 2 )
|
||||
// Set to middle of lower realtime priority range
|
||||
param.sched_priority = minp + (maxp - minp) / 4;
|
||||
else
|
||||
// Set to middle of higher realtime priority range
|
||||
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
FileInputStream in (*this);
|
||||
|
||||
if (dest.deleteFile())
|
||||
{
|
||||
{
|
||||
FileOutputStream out (dest);
|
||||
|
||||
if (out.failedToOpen())
|
||||
return false;
|
||||
|
||||
if (out.writeFromInputStream (in, -1) == getSize())
|
||||
return true;
|
||||
}
|
||||
|
||||
dest.deleteFile();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return getFileName().startsWithChar ('.');
|
||||
}
|
||||
|
||||
static String getLinkedFile (StringRef file)
|
||||
{
|
||||
HeapBlock<char> buffer (8194);
|
||||
const int numBytes = (int) readlink (file.text, buffer, 8192);
|
||||
return String::fromUTF8 (buffer, jmax (0, numBytes));
|
||||
};
|
||||
|
||||
bool File::isLink() const
|
||||
{
|
||||
return getLinkedFile (getFullPathName()).isNotEmpty();
|
||||
}
|
||||
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
String f (getLinkedFile (getFullPathName()));
|
||||
|
||||
if (f.isNotEmpty())
|
||||
return getSiblingFile (f);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wc)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8()))
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (dir != nullptr)
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
if (dir != nullptr)
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct dirent* const de = readdir (dir);
|
||||
|
||||
if (de == nullptr)
|
||||
break;
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||
{
|
||||
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||
|
||||
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = filenameFound.startsWithChar ('.');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
DIR* dir;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator() {}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* isDir, bool* isHidden, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||
};
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||
{
|
||||
switch (buf.f_type)
|
||||
{
|
||||
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||
return false;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume so if this fails for some reason
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
jassertfalse; // xxx not implemented for linux!
|
||||
return false;
|
||||
}
|
||||
|
||||
String File::getVersion() const
|
||||
{
|
||||
return String(); // xxx not yet implemented
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||
{
|
||||
StringArray confLines;
|
||||
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||
|
||||
for (int i = 0; i < confLines.size(); ++i)
|
||||
{
|
||||
const String line (confLines[i].trimStart());
|
||||
|
||||
if (line.startsWith (type))
|
||||
{
|
||||
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||
.fromFirstOccurrenceOf ("=", false, false)
|
||||
.trim().unquoted());
|
||||
|
||||
if (f.isDirectory())
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return File (fallbackFolder);
|
||||
}
|
||||
|
||||
const char* const* juce_argv = nullptr;
|
||||
int juce_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
{
|
||||
if (const char* homeDir = getenv ("HOME"))
|
||||
return File (CharPointer_UTF8 (homeDir));
|
||||
|
||||
if (struct passwd* const pw = getpwuid (getuid()))
|
||||
return File (CharPointer_UTF8 (pw->pw_dir));
|
||||
|
||||
return File();
|
||||
}
|
||||
|
||||
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
|
||||
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
|
||||
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
|
||||
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
|
||||
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||
case userApplicationDataDirectory: return resolveXDGFolder ("XDG_CONFIG_HOME", "~");
|
||||
case commonDocumentsDirectory:
|
||||
case commonApplicationDataDirectory: return File ("/var");
|
||||
case globalApplicationsDirectory: return File ("/usr");
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp ("/var/tmp");
|
||||
|
||||
if (! tmp.isDirectory())
|
||||
{
|
||||
tmp = "/tmp";
|
||||
|
||||
if (! tmp.isDirectory())
|
||||
tmp = File::getCurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (juce_argv != nullptr && juce_argc > 0)
|
||||
return File (CharPointer_UTF8 (juce_argv[0]));
|
||||
// deliberate fall-through...
|
||||
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
return juce_getExecutableFile();
|
||||
|
||||
case hostApplicationPath:
|
||||
{
|
||||
const File f ("/proc/self/exe");
|
||||
return f.isLink() ? f.getLinkedTarget() : juce_getExecutableFile();
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return File();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
File trashCan ("~/.Trash");
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
trashCan = "~/.local/share/Trash/files";
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
return false;
|
||||
|
||||
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||
getFileExtension()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool isFileExecutable (const String& filename)
|
||||
{
|
||||
juce_statStruct info;
|
||||
|
||||
return juce_stat (filename, info)
|
||||
&& S_ISREG (info.st_mode)
|
||||
&& access (filename.toUTF8(), X_OK) == 0;
|
||||
}
|
||||
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
String cmdString (fileName.replace (" ", "\\ ",false));
|
||||
cmdString << " " << parameters;
|
||||
|
||||
if (URL::isProbablyAWebsiteURL (fileName)
|
||||
|| cmdString.startsWithIgnoreCase ("file:")
|
||||
|| URL::isProbablyAnEmailAddress (fileName)
|
||||
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||
|| ! isFileExecutable (fileName))
|
||||
{
|
||||
// create a command that tries to launch a bunch of likely browsers
|
||||
static const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||
"google-chrome", "chromium-browser", "opera", "konqueror" };
|
||||
StringArray cmdLines;
|
||||
|
||||
for (int i = 0; i < numElementsInArray (browserNames); ++i)
|
||||
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
|
||||
|
||||
cmdString = cmdLines.joinIntoString (" || ");
|
||||
}
|
||||
|
||||
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
|
||||
|
||||
const int cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
setsid();
|
||||
|
||||
// Child process
|
||||
execve (argv[0], (char**) argv, environ);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
return cpid >= 0;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
if (isDirectory())
|
||||
startAsProcess();
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().startAsProcess();
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
const int s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
if (s != -1)
|
||||
{
|
||||
struct ifaddrs* addrs = nullptr;
|
||||
|
||||
if (getifaddrs (&addrs) != -1)
|
||||
{
|
||||
for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy (ifr.ifr_name, i->ifa_name);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
|
||||
{
|
||||
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
|
||||
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs (addrs);
|
||||
}
|
||||
|
||||
close (s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
|
||||
const String& /* emailSubject */,
|
||||
const String& /* bodyText */,
|
||||
const StringArray& /* filesToAttach */)
|
||||
{
|
||||
jassertfalse; // xxx todo
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: statusCode (0), socketHandle (-1), levelsOfRedirection (0),
|
||||
address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
statusCode = createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (responseHeaders != nullptr && ! isError())
|
||||
{
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String& headersEntry = headerLines[i];
|
||||
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return socketHandle < 0; }
|
||||
bool isExhausted() override { return finished; }
|
||||
int64 getPosition() override { return position; }
|
||||
|
||||
int64 getTotalLength() override
|
||||
{
|
||||
//xxx to do
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read (void* buffer, int bytesToRead) override
|
||||
{
|
||||
if (finished || isError())
|
||||
return 0;
|
||||
|
||||
fd_set readbits;
|
||||
FD_ZERO (&readbits);
|
||||
FD_SET (socketHandle, &readbits);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = jmax (1, timeOutMs / 1000);
|
||||
tv.tv_usec = 0;
|
||||
|
||||
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||
return 0; // (timeout)
|
||||
|
||||
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
|
||||
position += bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos) override
|
||||
{
|
||||
if (isError())
|
||||
return false;
|
||||
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
closeSocket();
|
||||
position = 0;
|
||||
statusCode = createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int statusCode;
|
||||
|
||||
private:
|
||||
int socketHandle, levelsOfRedirection;
|
||||
StringArray headerLines;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
const int timeOutMs;
|
||||
|
||||
void closeSocket()
|
||||
{
|
||||
if (socketHandle >= 0)
|
||||
close (socketHandle);
|
||||
|
||||
socketHandle = -1;
|
||||
levelsOfRedirection = 0;
|
||||
}
|
||||
|
||||
int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||
{
|
||||
closeSocket();
|
||||
|
||||
uint32 timeOutTime = Time::getMillisecondCounter();
|
||||
|
||||
if (timeOutMs == 0)
|
||||
timeOutTime += 60000;
|
||||
else if (timeOutMs < 0)
|
||||
timeOutTime = 0xffffffff;
|
||||
else
|
||||
timeOutTime += timeOutMs;
|
||||
|
||||
String hostName, hostPath;
|
||||
int hostPort;
|
||||
if (! decomposeURL (address, hostName, hostPath, hostPort))
|
||||
return 0;
|
||||
|
||||
String serverName, proxyName, proxyPath;
|
||||
int proxyPort = 0;
|
||||
int port = 0;
|
||||
|
||||
const String proxyURL (getenv ("http_proxy"));
|
||||
if (proxyURL.startsWithIgnoreCase ("http://"))
|
||||
{
|
||||
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
|
||||
return 0;
|
||||
|
||||
serverName = proxyName;
|
||||
port = proxyPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
serverName = hostName;
|
||||
port = hostPort;
|
||||
}
|
||||
|
||||
struct addrinfo hints;
|
||||
zerostruct (hints);
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
|
||||
struct addrinfo* result = nullptr;
|
||||
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
|
||||
return 0;
|
||||
|
||||
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
|
||||
|
||||
if (socketHandle == -1)
|
||||
{
|
||||
freeaddrinfo (result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int receiveBufferSize = 16384;
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
|
||||
|
||||
#if JUCE_MAC
|
||||
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
|
||||
#endif
|
||||
|
||||
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
|
||||
{
|
||||
closeSocket();
|
||||
freeaddrinfo (result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
freeaddrinfo (result);
|
||||
|
||||
{
|
||||
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
|
||||
hostPath, address, headers, postData, isPost));
|
||||
|
||||
if (! sendHeader (socketHandle, requestHeader, timeOutTime,
|
||||
progressCallback, progressCallbackContext))
|
||||
{
|
||||
closeSocket();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
String responseHeader (readResponse (timeOutTime));
|
||||
position = 0;
|
||||
|
||||
if (responseHeader.isNotEmpty())
|
||||
{
|
||||
headerLines = StringArray::fromLines (responseHeader);
|
||||
|
||||
const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false)
|
||||
.substring (0, 3).getIntValue();
|
||||
|
||||
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
|
||||
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
|
||||
|
||||
String location (findHeaderItem (headerLines, "Location:"));
|
||||
|
||||
if (status >= 300 && status < 400
|
||||
&& location.isNotEmpty() && location != address)
|
||||
{
|
||||
if (! location.startsWithIgnoreCase ("http://"))
|
||||
location = "http://" + location;
|
||||
|
||||
if (++levelsOfRedirection <= 3)
|
||||
{
|
||||
address = location;
|
||||
return createConnection (progressCallback, progressCallbackContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
levelsOfRedirection = 0;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
closeSocket();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String readResponse (const uint32 timeOutTime)
|
||||
{
|
||||
int numConsecutiveLFs = 0;
|
||||
MemoryOutputStream buffer;
|
||||
|
||||
while (numConsecutiveLFs < 2
|
||||
&& buffer.getDataSize() < 32768
|
||||
&& Time::getMillisecondCounter() <= timeOutTime
|
||||
&& ! (finished || isError()))
|
||||
{
|
||||
char c = 0;
|
||||
if (read (&c, 1) != 1)
|
||||
return String();
|
||||
|
||||
buffer.writeByte (c);
|
||||
|
||||
if (c == '\n')
|
||||
++numConsecutiveLFs;
|
||||
else if (c != '\r')
|
||||
numConsecutiveLFs = 0;
|
||||
}
|
||||
|
||||
const String header (buffer.toString().trimEnd());
|
||||
|
||||
if (header.startsWithIgnoreCase ("HTTP/"))
|
||||
return header;
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
|
||||
{
|
||||
if (! headers.containsIgnoreCase (key))
|
||||
dest << "\r\n" << key << ' ' << value;
|
||||
}
|
||||
|
||||
static void writeHost (MemoryOutputStream& dest, const bool isPost,
|
||||
const String& path, const String& host, int /*port*/)
|
||||
{
|
||||
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
|
||||
}
|
||||
|
||||
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
|
||||
const String& proxyName, const int proxyPort,
|
||||
const String& hostPath, const String& originalURL,
|
||||
const String& userHeaders, const MemoryBlock& postData,
|
||||
const bool isPost)
|
||||
{
|
||||
MemoryOutputStream header;
|
||||
|
||||
if (proxyName.isEmpty())
|
||||
writeHost (header, isPost, hostPath, hostName, hostPort);
|
||||
else
|
||||
writeHost (header, isPost, originalURL, proxyName, proxyPort);
|
||||
|
||||
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "JUCE/" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
|
||||
"." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
|
||||
"." JUCE_STRINGIFY(JUCE_BUILDNUMBER));
|
||||
writeValueIfNotPresent (header, userHeaders, "Connection:", "close");
|
||||
|
||||
if (isPost)
|
||||
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
|
||||
|
||||
header << "\r\n" << userHeaders
|
||||
<< "\r\n" << postData;
|
||||
|
||||
return header.getMemoryBlock();
|
||||
}
|
||||
|
||||
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||
{
|
||||
size_t totalHeaderSent = 0;
|
||||
|
||||
while (totalHeaderSent < requestHeader.getSize())
|
||||
{
|
||||
if (Time::getMillisecondCounter() > timeOutTime)
|
||||
return false;
|
||||
|
||||
const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
|
||||
|
||||
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
|
||||
return false;
|
||||
|
||||
totalHeaderSent += numToSend;
|
||||
|
||||
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool decomposeURL (const String& url, String& host, String& path, int& port)
|
||||
{
|
||||
if (! url.startsWithIgnoreCase ("http://"))
|
||||
return false;
|
||||
|
||||
const int nextSlash = url.indexOfChar (7, '/');
|
||||
int nextColon = url.indexOfChar (7, ':');
|
||||
if (nextColon > nextSlash && nextSlash > 0)
|
||||
nextColon = -1;
|
||||
|
||||
if (nextColon >= 0)
|
||||
{
|
||||
host = url.substring (7, nextColon);
|
||||
|
||||
if (nextSlash >= 0)
|
||||
port = url.substring (nextColon + 1, nextSlash).getIntValue();
|
||||
else
|
||||
port = url.substring (nextColon + 1).getIntValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
port = 80;
|
||||
|
||||
if (nextSlash >= 0)
|
||||
host = url.substring (7, nextSlash);
|
||||
else
|
||||
host = url.substring (7);
|
||||
}
|
||||
|
||||
if (nextSlash >= 0)
|
||||
path = url.substring (nextSlash);
|
||||
else
|
||||
path = "/";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static String findHeaderItem (const StringArray& lines, const String& itemName)
|
||||
{
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
if (lines[i].startsWithIgnoreCase (itemName))
|
||||
return lines[i].substring (itemName.length()).trim();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Linux;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Linux";
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
//xxx not sure how to find this out?..
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace LinuxStatsHelpers
|
||||
{
|
||||
String getCpuInfo (const char* const key)
|
||||
{
|
||||
StringArray lines;
|
||||
File ("/proc/cpuinfo").readLines (lines);
|
||||
|
||||
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||
if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase (key))
|
||||
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
|
||||
|
||||
return String();
|
||||
}
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return LinuxStatsHelpers::getCpuInfo ("Hardware");
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
String v (LinuxStatsHelpers::getCpuInfo ("vendor_id"));
|
||||
|
||||
if (v.isEmpty())
|
||||
v = LinuxStatsHelpers::getCpuInfo ("model name");
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return sysi.totalram * sysi.mem_unit / (1024 * 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (const char* user = getenv ("USER"))
|
||||
return CharPointer_UTF8 (user);
|
||||
|
||||
if (struct passwd* const pw = getpwuid (getuid()))
|
||||
return CharPointer_UTF8 (pw->pw_name);
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
static String getLocaleValue (nl_item key)
|
||||
{
|
||||
const char* oldLocale = ::setlocale (LC_ALL, "");
|
||||
String result (String::fromUTF8 (nl_langinfo (key)));
|
||||
::setlocale (LC_ALL, oldLocale);
|
||||
return result;
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
|
||||
hasMMX = flags.contains ("mmx");
|
||||
hasSSE = flags.contains ("sse");
|
||||
hasSSE2 = flags.contains ("sse2");
|
||||
hasSSE3 = flags.contains ("sse3");
|
||||
has3DNow = flags.contains ("3dnow");
|
||||
|
||||
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
timeval t;
|
||||
t.tv_sec = millisSinceEpoch / 1000;
|
||||
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
|
||||
|
||||
return settimeofday (&t, 0) == 0;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
|
||||
{
|
||||
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||
const int minp = sched_get_priority_min (policy);
|
||||
const int maxp = sched_get_priority_max (policy);
|
||||
|
||||
struct sched_param param;
|
||||
|
||||
switch (prior)
|
||||
{
|
||||
case LowPriority:
|
||||
case NormalPriority: param.sched_priority = 0; break;
|
||||
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return false;
|
||||
#else
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
|
||||
|
||||
if (testResult >= 0)
|
||||
{
|
||||
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||
testResult = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return testResult < 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
static bool swapUserAndEffectiveUser()
|
||||
{
|
||||
int result1 = setreuid (geteuid(), getuid());
|
||||
int result2 = setregid (getegid(), getgid());
|
||||
return result1 == 0 && result2 == 0;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSFileManager* fm = [NSFileManager defaultManager];
|
||||
|
||||
return [fm fileExistsAtPath: juceStringToNS (fullPath)]
|
||||
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
&& [fm copyItemAtPath: juceStringToNS (fullPath)
|
||||
toPath: juceStringToNS (dest.getFullPathName())
|
||||
error: nil];
|
||||
#else
|
||||
&& [fm copyPath: juceStringToNS (fullPath)
|
||||
toPath: juceStringToNS (dest.getFullPathName())
|
||||
handler: nil];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
namespace FileHelpers
|
||||
{
|
||||
static bool isFileOnDriveType (const File& f, const char* const* types)
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (juce_doStatFS (f, buf))
|
||||
{
|
||||
const String type (buf.f_fstypename);
|
||||
|
||||
while (*types != 0)
|
||||
if (type.equalsIgnoreCase (*types++))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isHiddenFile (const String& path)
|
||||
{
|
||||
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSNumber* hidden = nil;
|
||||
NSError* err = nil;
|
||||
|
||||
return [[NSURL fileURLWithPath: juceStringToNS (path)]
|
||||
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
|
||||
&& [hidden boolValue];
|
||||
}
|
||||
#elif JUCE_IOS
|
||||
return File (path).getFileName().startsWithChar ('.');
|
||||
#else
|
||||
FSRef ref;
|
||||
LSItemInfoRecord info;
|
||||
|
||||
return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
|
||||
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
|
||||
&& (info.flags & kLSItemInfoIsInvisible) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JUCE_IOS
|
||||
static String getIOSSystemLocation (NSSearchPathDirectory type)
|
||||
{
|
||||
return nsStringToJuce ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
|
||||
objectAtIndex: 0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool launchExecutable (const String& pathAndArguments)
|
||||
{
|
||||
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
|
||||
|
||||
const int cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
// Child process
|
||||
if (execve (argv[0], (char**) argv, 0) < 0)
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpid < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", nullptr };
|
||||
|
||||
return FileHelpers::isFileOnDriveType (*this, cdTypes);
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", nullptr };
|
||||
|
||||
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return false; // xxx is this possible?
|
||||
#else
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
BOOL removable = false;
|
||||
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
getFileSystemInfoForPath: juceStringToNS (getFullPathName())
|
||||
isRemovable: &removable
|
||||
isWritable: nil
|
||||
isUnmountable: nil
|
||||
description: nil
|
||||
type: nil];
|
||||
|
||||
return removable;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return FileHelpers::isHiddenFile (getFullPathName());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const* juce_argv = nullptr;
|
||||
int juce_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
String resultPath;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
|
||||
|
||||
#if JUCE_IOS
|
||||
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return tmp.getFullPathName();
|
||||
}
|
||||
|
||||
#else
|
||||
case userDocumentsDirectory: resultPath = "~/Documents"; break;
|
||||
case userDesktopDirectory: resultPath = "~/Desktop"; break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp ("~/Library/Caches/" + juce_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return File (tmp.getFullPathName());
|
||||
}
|
||||
#endif
|
||||
case userMusicDirectory: resultPath = "~/Music"; break;
|
||||
case userMoviesDirectory: resultPath = "~/Movies"; break;
|
||||
case userPicturesDirectory: resultPath = "~/Pictures"; break;
|
||||
case userApplicationDataDirectory: resultPath = "~/Library"; break;
|
||||
case commonApplicationDataDirectory: resultPath = "/Library"; break;
|
||||
case commonDocumentsDirectory: resultPath = "/Users/Shared"; break;
|
||||
case globalApplicationsDirectory: resultPath = "/Applications"; break;
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (juce_argv != nullptr && juce_argc > 0)
|
||||
return File (CharPointer_UTF8 (juce_argv[0]));
|
||||
// deliberate fall-through...
|
||||
|
||||
case currentExecutableFile:
|
||||
return juce_getExecutableFile();
|
||||
|
||||
case currentApplicationFile:
|
||||
{
|
||||
const File exe (juce_getExecutableFile());
|
||||
const File parent (exe.getParentDirectory());
|
||||
|
||||
#if JUCE_IOS
|
||||
return parent;
|
||||
#else
|
||||
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
|
||||
? parent.getParentDirectory().getParentDirectory()
|
||||
: exe;
|
||||
#endif
|
||||
}
|
||||
|
||||
case hostApplicationPath:
|
||||
{
|
||||
unsigned int size = 8192;
|
||||
HeapBlock<char> buffer;
|
||||
buffer.calloc (size + 8);
|
||||
|
||||
_NSGetExecutablePath (buffer.getData(), &size);
|
||||
return File (String::fromUTF8 (buffer, (int) size));
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
if (resultPath.isNotEmpty())
|
||||
return File (resultPath.convertToPrecomposedUnicode());
|
||||
}
|
||||
|
||||
return File();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String File::getVersion() const
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
if (NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())])
|
||||
if (NSDictionary* info = [bundle infoDictionary])
|
||||
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
|
||||
return nsStringToJuce (name);
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static NSString* getFileLink (const String& path)
|
||||
{
|
||||
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (path) error: nil];
|
||||
#else
|
||||
// (the cast here avoids a deprecation warning)
|
||||
return [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (path)];
|
||||
#endif
|
||||
}
|
||||
|
||||
bool File::isLink() const
|
||||
{
|
||||
return getFileLink (fullPath) != nil;
|
||||
}
|
||||
|
||||
File File::getLinkedTarget() const
|
||||
{
|
||||
if (NSString* dest = getFileLink (fullPath))
|
||||
return getSiblingFile (nsStringToJuce (dest));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
#if JUCE_IOS
|
||||
return deleteFile(); //xxx is there a trashcan on the iOS?
|
||||
#else
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSString* p = juceStringToNS (getFullPathName());
|
||||
|
||||
return [[NSWorkspace sharedWorkspace]
|
||||
performFileOperation: NSWorkspaceRecycleOperation
|
||||
source: [p stringByDeletingLastPathComponent]
|
||||
destination: nsEmptyString()
|
||||
files: [NSArray arrayWithObject: [p lastPathComponent]]
|
||||
tag: nil ];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wildCard_)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wildCard_),
|
||||
enumerator (nil)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: juceStringToNS (directory.getFullPathName())] retain];
|
||||
}
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
[enumerator release];
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NSString* file;
|
||||
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
|
||||
return false;
|
||||
|
||||
[enumerator skipDescendents];
|
||||
filenameFound = nsStringToJuce (file).convertToPrecomposedUnicode();
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
|
||||
continue;
|
||||
|
||||
const String fullPath (parentDir + filenameFound);
|
||||
updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = FileHelpers::isHiddenFile (fullPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
NSDirectoryEnumerator* enumerator;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSURL* filenameAsURL = [NSURL URLWithString: juceStringToNS (fileName)];
|
||||
|
||||
#if JUCE_IOS
|
||||
(void) parameters;
|
||||
return [[UIApplication sharedApplication] openURL: filenameAsURL];
|
||||
#else
|
||||
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||
|
||||
if (parameters.isEmpty())
|
||||
return [workspace openFile: juceStringToNS (fileName)]
|
||||
|| [workspace openURL: filenameAsURL];
|
||||
|
||||
const File file (fileName);
|
||||
|
||||
if (file.isBundle())
|
||||
{
|
||||
StringArray params;
|
||||
params.addTokens (parameters, true);
|
||||
|
||||
NSMutableArray* paramArray = [[[NSMutableArray alloc] init] autorelease];
|
||||
for (int i = 0; i < params.size(); ++i)
|
||||
[paramArray addObject: juceStringToNS (params[i])];
|
||||
|
||||
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
[dict setObject: paramArray
|
||||
forKey: nsStringLiteral ("NSWorkspaceLaunchConfigurationArguments")];
|
||||
|
||||
return [workspace launchApplicationAtURL: filenameAsURL
|
||||
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
|
||||
configuration: dict
|
||||
error: nil];
|
||||
}
|
||||
|
||||
if (file.exists())
|
||||
return FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
#if ! JUCE_IOS
|
||||
if (exists())
|
||||
[[NSWorkspace sharedWorkspace] selectFile: juceStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().revealToUser();
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
OSType File::getMacOSType() const
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: juceStringToNS (getFullPathName()) error: nil];
|
||||
#else
|
||||
// (the cast here avoids a deprecation warning)
|
||||
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: juceStringToNS (getFullPathName()) traverseLink: NO];
|
||||
#endif
|
||||
|
||||
return [fileDict fileHFSTypeCode];
|
||||
}
|
||||
}
|
||||
|
||||
bool File::isBundle() const
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
|
||||
#else
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (getFullPathName())];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
void File::addToDock() const
|
||||
{
|
||||
// check that it's not already there...
|
||||
if (! juce_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
|
||||
{
|
||||
juce_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
|
||||
+ getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
|
||||
|
||||
juce_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
ifaddrs* addrs = nullptr;
|
||||
|
||||
if (getifaddrs (&addrs) == 0)
|
||||
{
|
||||
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
|
||||
{
|
||||
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
|
||||
if (sto->ss_family == AF_LINK)
|
||||
{
|
||||
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
||||
|
||||
#ifndef IFT_ETHER
|
||||
enum { IFT_ETHER = 6 };
|
||||
#endif
|
||||
|
||||
if (sadd->sdl_type == IFT_ETHER)
|
||||
{
|
||||
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs (addrs);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
(void) targetEmailAddress;
|
||||
(void) emailSubject;
|
||||
(void) bodyText;
|
||||
(void) filesToAttach;
|
||||
|
||||
//xxx probably need to use MFMailComposeViewController
|
||||
jassertfalse;
|
||||
return false;
|
||||
#else
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject.replace ("\"", "\\\"")
|
||||
<< "\", content:\""
|
||||
<< bodyText.replace ("\"", "\\\"")
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i].replace ("\"", "\\\"")
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
NSAppleScript* s = [[NSAppleScript alloc] initWithSource: juceStringToNS (script)];
|
||||
NSDictionary* error = nil;
|
||||
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||
[s release];
|
||||
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class URLConnectionState : public Thread
|
||||
{
|
||||
public:
|
||||
URLConnectionState (NSURLRequest* req)
|
||||
: Thread ("http connection"),
|
||||
contentLength (-1),
|
||||
delegate (nil),
|
||||
request ([req retain]),
|
||||
connection (nil),
|
||||
data ([[NSMutableData data] retain]),
|
||||
headers (nil),
|
||||
statusCode (0),
|
||||
initialised (false),
|
||||
hasFailed (false),
|
||||
hasFinished (false)
|
||||
{
|
||||
static DelegateClass cls;
|
||||
delegate = [cls.createInstance() init];
|
||||
DelegateClass::setState (delegate, this);
|
||||
}
|
||||
|
||||
~URLConnectionState()
|
||||
{
|
||||
stop();
|
||||
[connection release];
|
||||
[data release];
|
||||
[request release];
|
||||
[headers release];
|
||||
[delegate release];
|
||||
}
|
||||
|
||||
bool start (URL::OpenStreamProgressCallback* callback, void* context)
|
||||
{
|
||||
startThread();
|
||||
|
||||
while (isThreadRunning() && ! initialised)
|
||||
{
|
||||
if (callback != nullptr)
|
||||
callback (context, -1, (int) [[request HTTPBody] length]);
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
return connection != nil && ! hasFailed;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
[connection cancel];
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
int read (char* dest, int numBytes)
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numBytes > 0)
|
||||
{
|
||||
const int available = jmin (numBytes, (int) [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data getBytes: dest length: (NSUInteger) available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||
|
||||
numDone += available;
|
||||
numBytes -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
return numDone;
|
||||
}
|
||||
|
||||
void didReceiveResponse (NSURLResponse* response)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data setLength: 0];
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
contentLength = [response expectedContentLength];
|
||||
|
||||
[headers release];
|
||||
headers = nil;
|
||||
|
||||
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||
{
|
||||
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
|
||||
headers = [[httpResponse allHeaderFields] retain];
|
||||
statusCode = (int) [httpResponse statusCode];
|
||||
}
|
||||
}
|
||||
|
||||
void didFailWithError (NSError* error)
|
||||
{
|
||||
DBG (nsStringToJuce ([error description])); (void) error;
|
||||
hasFailed = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void didReceiveData (NSData* newData)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data appendData: newData];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void didSendBodyData (NSInteger /*totalBytesWritten*/, NSInteger /*totalBytesExpected*/)
|
||||
{
|
||||
}
|
||||
|
||||
void finishedLoading()
|
||||
{
|
||||
hasFinished = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: delegate];
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64 contentLength;
|
||||
CriticalSection dataLock;
|
||||
NSObject* delegate;
|
||||
NSURLRequest* request;
|
||||
NSURLConnection* connection;
|
||||
NSMutableData* data;
|
||||
NSDictionary* headers;
|
||||
int statusCode;
|
||||
bool initialised, hasFailed, hasFinished;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
|
||||
{
|
||||
addIvar<URLConnectionState*> ("state");
|
||||
|
||||
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
||||
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
||||
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
||||
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||
connectionDidSendBodyData, "v@:@iii");
|
||||
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
||||
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
|
||||
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
||||
|
||||
private:
|
||||
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||
{
|
||||
getState (self)->didReceiveResponse (response);
|
||||
}
|
||||
|
||||
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||
{
|
||||
getState (self)->didFailWithError (error);
|
||||
}
|
||||
|
||||
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||
{
|
||||
getState (self)->didReceiveData (newData);
|
||||
}
|
||||
|
||||
static NSURLRequest* willSendRequest (id, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse*)
|
||||
{
|
||||
return request;
|
||||
}
|
||||
|
||||
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||
{
|
||||
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||
}
|
||||
|
||||
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||
{
|
||||
getState (self)->finishedLoading();
|
||||
}
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: statusCode (0), address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
|
||||
{
|
||||
statusCode = connection->statusCode;
|
||||
|
||||
NSEnumerator* enumerator = [connection->headers keyEnumerator];
|
||||
|
||||
while (NSString* key = [enumerator nextObject])
|
||||
responseHeaders->set (nsStringToJuce (key),
|
||||
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return connection == nullptr; }
|
||||
int64 getTotalLength() override { return connection == nullptr ? -1 : connection->contentLength; }
|
||||
bool isExhausted() override { return finished; }
|
||||
int64 getPosition() override { return position; }
|
||||
|
||||
int read (void* buffer, int bytesToRead) override
|
||||
{
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (finished || isError())
|
||||
return 0;
|
||||
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
const int bytesRead = connection->read (static_cast<char*> (buffer), bytesToRead);
|
||||
position += bytesRead;
|
||||
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos) override
|
||||
{
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
connection = nullptr;
|
||||
position = 0;
|
||||
createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int statusCode;
|
||||
|
||||
private:
|
||||
ScopedPointer<URLConnectionState> connection;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
const int timeOutMs;
|
||||
|
||||
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||
{
|
||||
jassert (connection == nullptr);
|
||||
|
||||
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
|
||||
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
||||
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||
|
||||
if (req != nil)
|
||||
{
|
||||
[req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
|
||||
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||
|
||||
StringArray headerLines;
|
||||
headerLines.addLines (headers);
|
||||
headerLines.removeEmptyStrings (true);
|
||||
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
|
||||
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
|
||||
|
||||
if (key.isNotEmpty() && value.isNotEmpty())
|
||||
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
|
||||
}
|
||||
|
||||
if (isPost && postData.getSize() > 0)
|
||||
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||
length: postData.getSize()]];
|
||||
|
||||
connection = new URLConnectionState (req);
|
||||
|
||||
if (! connection->start (progressCallback, progressCallbackContext))
|
||||
connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
String String::fromCFString (CFStringRef cfString)
|
||||
{
|
||||
if (cfString == 0)
|
||||
return String();
|
||||
|
||||
CFRange range = { 0, CFStringGetLength (cfString) };
|
||||
CFIndex bytesNeeded = 0;
|
||||
CFStringGetBytes (cfString, range, kCFStringEncodingUTF8, 0, false, nullptr, 0, &bytesNeeded);
|
||||
|
||||
HeapBlock<UInt8> utf8 ((size_t) bytesNeeded + 1);
|
||||
CFStringGetBytes (cfString, range, kCFStringEncodingUTF8, 0, false, utf8, bytesNeeded + 1, nullptr);
|
||||
|
||||
return String (CharPointer_UTF8 ((const CharPointer_UTF8::CharType*) utf8.getData()),
|
||||
CharPointer_UTF8 ((const CharPointer_UTF8::CharType*) utf8.getData() + bytesNeeded));
|
||||
}
|
||||
|
||||
CFStringRef String::toCFString() const
|
||||
{
|
||||
const char* const utf8 = toRawUTF8();
|
||||
return CFStringCreateWithBytes (kCFAllocatorDefault, (const UInt8*) utf8,
|
||||
(CFIndex) strlen (utf8), kCFStringEncodingUTF8, false);
|
||||
}
|
||||
|
||||
String String::convertToPrecomposedUnicode() const
|
||||
{
|
||||
#if JUCE_IOS
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
return nsStringToJuce ([juceStringToNS (*this) precomposedStringWithCanonicalMapping]);
|
||||
}
|
||||
#else
|
||||
UnicodeMapping map;
|
||||
|
||||
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||
kUnicodeNoSubset,
|
||||
kTextEncodingDefaultFormat);
|
||||
|
||||
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||
kUnicodeCanonicalCompVariant,
|
||||
kTextEncodingDefaultFormat);
|
||||
|
||||
map.mappingVersion = kUnicodeUseLatestMapping;
|
||||
|
||||
UnicodeToTextInfo conversionInfo = 0;
|
||||
String result;
|
||||
|
||||
if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
|
||||
{
|
||||
const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
|
||||
|
||||
HeapBlock<char> tempOut;
|
||||
tempOut.calloc (bytesNeeded + 4);
|
||||
|
||||
ByteCount bytesRead = 0;
|
||||
ByteCount outputBufferSize = 0;
|
||||
|
||||
if (ConvertFromUnicodeToText (conversionInfo,
|
||||
bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
|
||||
kUnicodeDefaultDirectionMask,
|
||||
0, 0, 0, 0,
|
||||
bytesNeeded, &bytesRead,
|
||||
&outputBufferSize, tempOut) == noErr)
|
||||
{
|
||||
result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
|
||||
}
|
||||
|
||||
DisposeUnicodeToTextInfo (&conversionInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
ScopedAutoReleasePool::ScopedAutoReleasePool()
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
ScopedAutoReleasePool::~ScopedAutoReleasePool()
|
||||
{
|
||||
[((NSAutoreleasePool*) pool) release];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
// Would prefer to use std::cerr here, but avoiding it for
|
||||
// the moment, due to clang JIT linkage problems.
|
||||
fputs (text.toRawUTF8(), stderr);
|
||||
fputs ("\n", stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace SystemStatsHelpers
|
||||
{
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||
{
|
||||
uint32 la = a, lb = b, lc = c, ld = d;
|
||||
|
||||
asm ("mov %%ebx, %%esi \n\t"
|
||||
"cpuid \n\t"
|
||||
"xchg %%esi, %%ebx"
|
||||
: "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
|
||||
#if JUCE_64BIT
|
||||
, "b" (lb), "c" (lc), "d" (ld)
|
||||
#endif
|
||||
);
|
||||
|
||||
a = la; b = lb; c = lc; d = ld;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
uint32 a = 0, b = 0, d = 0, c = 0;
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
|
||||
|
||||
hasMMX = (d & (1u << 23)) != 0;
|
||||
hasSSE = (d & (1u << 25)) != 0;
|
||||
hasSSE2 = (d & (1u << 26)) != 0;
|
||||
has3DNow = (b & (1u << 31)) != 0;
|
||||
hasSSE3 = (c & (1u << 0)) != 0;
|
||||
#endif
|
||||
|
||||
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
|
||||
#else
|
||||
numCpus = (int) MPProcessors();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
struct RLimitInitialiser
|
||||
{
|
||||
RLimitInitialiser()
|
||||
{
|
||||
rlimit lim;
|
||||
getrlimit (RLIMIT_NOFILE, &lim);
|
||||
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
|
||||
setrlimit (RLIMIT_NOFILE, &lim);
|
||||
}
|
||||
};
|
||||
|
||||
static RLimitInitialiser rLimitInitialiser;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_IOS
|
||||
static String getOSXVersion()
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
|
||||
|
||||
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return iOS;
|
||||
#else
|
||||
StringArray parts;
|
||||
parts.addTokens (getOSXVersion(), ".", StringRef());
|
||||
|
||||
jassert (parts[0].getIntValue() == 10);
|
||||
const int major = parts[1].getIntValue();
|
||||
jassert (major > 2);
|
||||
|
||||
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return "iOS " + nsStringToJuce ([[UIDevice currentDevice] systemVersion]);
|
||||
#else
|
||||
return "Mac OSX " + getOSXVersion();
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return nsStringToJuce ([[UIDevice currentDevice] model]);
|
||||
#else
|
||||
return String();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_IOS
|
||||
return false;
|
||||
#elif JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
return getOperatingSystemType() >= MacOSX_10_6;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
uint64 mem = 0;
|
||||
size_t memSize = sizeof (mem);
|
||||
int mib[] = { CTL_HW, HW_MEMSIZE };
|
||||
sysctl (mib, 2, &mem, &memSize, 0, 0);
|
||||
return (int) (mem / (1024 * 1024));
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
uint32 dummy = 0;
|
||||
uint32 vendor[4] = { 0 };
|
||||
|
||||
SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
|
||||
|
||||
return String (reinterpret_cast <const char*> (vendor), 12);
|
||||
#else
|
||||
return String();
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
uint64 speedHz = 0;
|
||||
size_t speedSize = sizeof (speedHz);
|
||||
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
||||
sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
if (speedSize == 4)
|
||||
speedHz >>= 32;
|
||||
#endif
|
||||
|
||||
return (int) (speedHz / 1000000);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
return nsStringToJuce (NSUserName());
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return nsStringToJuce (NSFullUserName());
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return String (name).upToLastOccurrenceOf (".local", false, true);
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
static String getLocaleValue (CFStringRef key)
|
||||
{
|
||||
CFLocaleRef cfLocale = CFLocaleCopyCurrent();
|
||||
const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
|
||||
CFRelease (cfLocale);
|
||||
return result;
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (kCFLocaleLanguageCode); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (kCFLocaleCountryCode); }
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
|
||||
const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
|
||||
CFRelease (cfPrefLangs);
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/* NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid
|
||||
division-by-zero errors if some other static constructor calls us before this file's
|
||||
static constructors have had a chance to fill them in correctly..
|
||||
*/
|
||||
static uint64 hiResCounterNumerator = 0, hiResCounterDenominator = 1;
|
||||
|
||||
class HiResCounterInfo
|
||||
{
|
||||
public:
|
||||
HiResCounterInfo()
|
||||
{
|
||||
mach_timebase_info_data_t timebase;
|
||||
(void) mach_timebase_info (&timebase);
|
||||
|
||||
if (timebase.numer % 1000000 == 0)
|
||||
{
|
||||
hiResCounterNumerator = timebase.numer / 1000000;
|
||||
hiResCounterDenominator = timebase.denom;
|
||||
}
|
||||
else
|
||||
{
|
||||
hiResCounterNumerator = timebase.numer;
|
||||
hiResCounterDenominator = timebase.denom * (uint64) 1000000;
|
||||
}
|
||||
|
||||
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
|
||||
highResTimerToMillisecRatio = hiResCounterNumerator / (double) hiResCounterDenominator;
|
||||
}
|
||||
|
||||
uint32 millisecondsSinceStartup() const noexcept
|
||||
{
|
||||
return (uint32) ((mach_absolute_time() * hiResCounterNumerator) / hiResCounterDenominator);
|
||||
}
|
||||
|
||||
double getMillisecondCounterHiRes() const noexcept
|
||||
{
|
||||
return mach_absolute_time() * highResTimerToMillisecRatio;
|
||||
}
|
||||
|
||||
int64 highResTimerFrequency;
|
||||
|
||||
private:
|
||||
double highResTimerToMillisecRatio;
|
||||
};
|
||||
|
||||
static HiResCounterInfo hiResCounterInfo;
|
||||
|
||||
uint32 juce_millisecondsSinceStartup() noexcept { return hiResCounterInfo.millisecondsSinceStartup(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterInfo.getMillisecondCounterHiRes(); }
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterInfo.highResTimerFrequency; }
|
||||
int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_absolute_time(); }
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return (int) NSPageSize();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
#if JUCE_IOS
|
||||
bool isIOSAppActive = true;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
return [NSApp isActive];
|
||||
#else
|
||||
return isIOSAppActive;
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
[NSApp activateIgnoringOtherApps: YES];
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::hide()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
[NSApp hide: nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority)
|
||||
{
|
||||
// xxx
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||
{
|
||||
static char testResult = 0;
|
||||
|
||||
if (testResult == 0)
|
||||
{
|
||||
struct kinfo_proc info;
|
||||
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
|
||||
size_t sz = sizeof (info);
|
||||
sysctl (m, 4, &info, &sz, 0, 0);
|
||||
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
return testResult > 0;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef JUCE_OSX_OBJCHELPERS_H_INCLUDED
|
||||
#define JUCE_OSX_OBJCHELPERS_H_INCLUDED
|
||||
|
||||
|
||||
/* This file contains a few helper functions that are used internally but which
|
||||
need to be kept away from the public headers because they use obj-C symbols.
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
//==============================================================================
|
||||
static inline String nsStringToJuce (NSString* s)
|
||||
{
|
||||
return CharPointer_UTF8 ([s UTF8String]);
|
||||
}
|
||||
|
||||
static inline NSString* juceStringToNS (const String& s)
|
||||
{
|
||||
return [NSString stringWithUTF8String: s.toUTF8()];
|
||||
}
|
||||
|
||||
static inline NSString* nsStringLiteral (const char* const s) noexcept
|
||||
{
|
||||
return [NSString stringWithUTF8String: s];
|
||||
}
|
||||
|
||||
static inline NSString* nsEmptyString() noexcept
|
||||
{
|
||||
return [NSString string];
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
template <typename RectangleType>
|
||||
static NSRect makeNSRect (const RectangleType& r) noexcept
|
||||
{
|
||||
return NSMakeRect (static_cast <CGFloat> (r.getX()),
|
||||
static_cast <CGFloat> (r.getY()),
|
||||
static_cast <CGFloat> (r.getWidth()),
|
||||
static_cast <CGFloat> (r.getHeight()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename ObjectType>
|
||||
struct NSObjectRetainer
|
||||
{
|
||||
inline NSObjectRetainer (ObjectType* o) : object (o) { [object retain]; }
|
||||
inline ~NSObjectRetainer() { [object release]; }
|
||||
|
||||
ObjectType* object;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename SuperclassType>
|
||||
struct ObjCClass
|
||||
{
|
||||
ObjCClass (const char* nameRoot)
|
||||
: cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
|
||||
{
|
||||
}
|
||||
|
||||
~ObjCClass()
|
||||
{
|
||||
objc_disposeClassPair (cls);
|
||||
}
|
||||
|
||||
void registerClass()
|
||||
{
|
||||
objc_registerClassPair (cls);
|
||||
}
|
||||
|
||||
SuperclassType* createInstance() const
|
||||
{
|
||||
return class_createInstance (cls, 0);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void addIvar (const char* name)
|
||||
{
|
||||
BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
|
||||
jassert (b); (void) b;
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
|
||||
{
|
||||
BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
|
||||
jassert (b); (void) b;
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
|
||||
{
|
||||
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
|
||||
}
|
||||
|
||||
void addProtocol (Protocol* protocol)
|
||||
{
|
||||
BOOL b = class_addProtocol (cls, protocol);
|
||||
jassert (b); (void) b;
|
||||
}
|
||||
|
||||
static id sendSuperclassMessage (id self, SEL selector)
|
||||
{
|
||||
objc_super s = { self, [SuperclassType class] };
|
||||
return objc_msgSendSuper (&s, selector);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static Type getIvar (id self, const char* name)
|
||||
{
|
||||
void* v = nullptr;
|
||||
object_getInstanceVariable (self, name, &v);
|
||||
return static_cast <Type> (v);
|
||||
}
|
||||
|
||||
Class cls;
|
||||
|
||||
private:
|
||||
static String getRandomisedName (const char* root)
|
||||
{
|
||||
return root + String::toHexString (juce::Random::getSystemRandom().nextInt64());
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ObjCClass)
|
||||
};
|
||||
|
||||
|
||||
#endif // JUCE_OSX_OBJCHELPERS_H_INCLUDED
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
class NamedPipe::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const String& pipePath, bool createPipe)
|
||||
: pipeInName (pipePath + "_in"),
|
||||
pipeOutName (pipePath + "_out"),
|
||||
pipeIn (-1), pipeOut (-1),
|
||||
createdPipe (createPipe),
|
||||
stopReadOperation (false)
|
||||
{
|
||||
signal (SIGPIPE, signalHandler);
|
||||
juce_siginterrupt (SIGPIPE, 1);
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (pipeIn != -1) ::close (pipeIn);
|
||||
if (pipeOut != -1) ::close (pipeOut);
|
||||
|
||||
if (createdPipe)
|
||||
{
|
||||
unlink (pipeInName.toUTF8());
|
||||
unlink (pipeOutName.toUTF8());
|
||||
}
|
||||
}
|
||||
|
||||
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
if (pipeIn == -1)
|
||||
{
|
||||
pipeIn = openPipe (createdPipe ? pipeInName : pipeOutName, O_RDWR | O_NONBLOCK, timeoutEnd);
|
||||
|
||||
if (pipeIn == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < maxBytesToRead)
|
||||
{
|
||||
const int bytesThisTime = maxBytesToRead - bytesRead;
|
||||
const int numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numRead <= 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK || stopReadOperation || hasExpired (timeoutEnd))
|
||||
return -1;
|
||||
|
||||
const int maxWaitingTime = 30;
|
||||
waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
|
||||
: jmin (maxWaitingTime,
|
||||
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||
continue;
|
||||
}
|
||||
|
||||
bytesRead += numRead;
|
||||
destBuffer += numRead;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
if (pipeOut == -1)
|
||||
{
|
||||
pipeOut = openPipe (createdPipe ? pipeOutName : pipeInName, O_WRONLY, timeoutEnd);
|
||||
|
||||
if (pipeOut == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
||||
{
|
||||
const int bytesThisTime = numBytesToWrite - bytesWritten;
|
||||
const int numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numWritten <= 0)
|
||||
return -1;
|
||||
|
||||
bytesWritten += numWritten;
|
||||
sourceBuffer += numWritten;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
bool createFifos() const
|
||||
{
|
||||
return (mkfifo (pipeInName .toUTF8(), 0666) == 0 || errno == EEXIST)
|
||||
&& (mkfifo (pipeOutName.toUTF8(), 0666) == 0 || errno == EEXIST);
|
||||
}
|
||||
|
||||
const String pipeInName, pipeOutName;
|
||||
int pipeIn, pipeOut;
|
||||
|
||||
const bool createdPipe;
|
||||
bool stopReadOperation;
|
||||
|
||||
private:
|
||||
static void signalHandler (int) {}
|
||||
|
||||
static uint32 getTimeoutEnd (const int timeOutMilliseconds)
|
||||
{
|
||||
return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
|
||||
}
|
||||
|
||||
static bool hasExpired (const uint32 timeoutEnd)
|
||||
{
|
||||
return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
|
||||
}
|
||||
|
||||
int openPipe (const String& name, int flags, const uint32 timeoutEnd)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const int p = ::open (name.toUTF8(), flags);
|
||||
|
||||
if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation)
|
||||
return p;
|
||||
|
||||
Thread::sleep (2);
|
||||
}
|
||||
}
|
||||
|
||||
static void waitForInput (const int handle, const int timeoutMsecs) noexcept
|
||||
{
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = timeoutMsecs / 1000;
|
||||
timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
|
||||
|
||||
fd_set rset;
|
||||
FD_ZERO (&rset);
|
||||
FD_SET (handle, &rset);
|
||||
|
||||
select (handle + 1, &rset, nullptr, 0, &timeout);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
void NamedPipe::close()
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
pimpl->stopReadOperation = true;
|
||||
|
||||
char buffer[1] = { 0 };
|
||||
ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
|
||||
(void) done;
|
||||
|
||||
ScopedWriteLock sl (lock);
|
||||
pimpl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory)
|
||||
.getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe);
|
||||
#else
|
||||
String file (pipeName);
|
||||
|
||||
if (! File::isAbsolutePath (file))
|
||||
file = "/tmp/" + File::createLegalFileName (file);
|
||||
|
||||
pimpl = new Pimpl (file, createPipe);
|
||||
#endif
|
||||
|
||||
if (createPipe && ! pimpl->createFifos())
|
||||
{
|
||||
pimpl = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->read (static_cast <char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->write (static_cast <const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef JUCE_WIN32_COMSMARTPTR_H_INCLUDED
|
||||
#define JUCE_WIN32_COMSMARTPTR_H_INCLUDED
|
||||
|
||||
#if ! (defined (_MSC_VER) || defined (__uuidof))
|
||||
template<typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } };
|
||||
#define __uuidof(x) UUIDGetter<x>::get()
|
||||
#endif
|
||||
|
||||
inline GUID uuidFromString (const char* const s) noexcept
|
||||
{
|
||||
unsigned long p0;
|
||||
unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
sscanf
|
||||
#else
|
||||
sscanf_s
|
||||
#endif
|
||||
(s, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
|
||||
|
||||
GUID g = { p0, (uint16) p1, (uint16) p2, { (uint8) p3, (uint8) p4, (uint8) p5, (uint8) p6,
|
||||
(uint8) p7, (uint8) p8, (uint8) p9, (uint8) p10 }};
|
||||
return g;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A simple COM smart pointer.
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComSmartPtr
|
||||
{
|
||||
public:
|
||||
ComSmartPtr() throw() : p (0) {}
|
||||
ComSmartPtr (ComClass* const obj) : p (obj) { if (p) p->AddRef(); }
|
||||
ComSmartPtr (const ComSmartPtr<ComClass>& other) : p (other.p) { if (p) p->AddRef(); }
|
||||
~ComSmartPtr() { release(); }
|
||||
|
||||
operator ComClass*() const throw() { return p; }
|
||||
ComClass& operator*() const throw() { return *p; }
|
||||
ComClass* operator->() const throw() { return p; }
|
||||
|
||||
ComSmartPtr& operator= (ComClass* const newP)
|
||||
{
|
||||
if (newP != 0) newP->AddRef();
|
||||
release();
|
||||
p = newP;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComSmartPtr& operator= (const ComSmartPtr<ComClass>& newP) { return operator= (newP.p); }
|
||||
|
||||
// Releases and nullifies this pointer and returns its address
|
||||
ComClass** resetAndGetPointerAddress()
|
||||
{
|
||||
release();
|
||||
p = 0;
|
||||
return &p;
|
||||
}
|
||||
|
||||
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
{
|
||||
HRESULT hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
|
||||
jassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
if (p == 0)
|
||||
return E_POINTER;
|
||||
|
||||
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
return this->QueryInterface (__uuidof (OtherComClass), destObject);
|
||||
}
|
||||
|
||||
private:
|
||||
ComClass* p;
|
||||
|
||||
void release() { if (p != 0) p->Release(); }
|
||||
|
||||
ComClass** operator&() throw(); // private to avoid it being used accidentally
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_COMRESULT HRESULT __stdcall
|
||||
|
||||
//==============================================================================
|
||||
template <class ComClass>
|
||||
class ComBaseClassHelperBase : public ComClass
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
|
||||
virtual ~ComBaseClassHelperBase() {}
|
||||
|
||||
ULONG __stdcall AddRef() { return ++refCount; }
|
||||
ULONG __stdcall Release() { const ULONG r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
protected:
|
||||
ULONG refCount;
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == IID_IUnknown)
|
||||
return castToType <IUnknown> (result);
|
||||
|
||||
*result = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
JUCE_COMRESULT castToType (void** result)
|
||||
{
|
||||
this->AddRef(); *result = dynamic_cast <Type*> (this); return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComBaseClassHelper : public ComBaseClassHelperBase <ComClass>
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelper (unsigned int initialRefCount = 1) : ComBaseClassHelperBase <ComClass> (initialRefCount) {}
|
||||
~ComBaseClassHelper() {}
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == __uuidof (ComClass))
|
||||
return this->template castToType <ComClass> (result);
|
||||
|
||||
return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // JUCE_WIN32_COMSMARTPTR_H_INCLUDED
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef INTERNET_FLAG_NEED_FILE
|
||||
#define INTERNET_FLAG_NEED_FILE 0x00000010
|
||||
#endif
|
||||
|
||||
#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
|
||||
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||
: statusCode (0), connection (0), request (0),
|
||||
address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
for (int maxRedirects = 10; --maxRedirects >= 0;)
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (! isError())
|
||||
{
|
||||
DWORD bufferSizeBytes = 4096;
|
||||
StringPairArray headers (false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HeapBlock<char> buffer ((size_t) bufferSizeBytes);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
|
||||
{
|
||||
StringArray headersArray;
|
||||
headersArray.addLines (String (reinterpret_cast<const WCHAR*> (buffer.getData())));
|
||||
|
||||
for (int i = 0; i < headersArray.size(); ++i)
|
||||
{
|
||||
const String& header = headersArray[i];
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue (headers[key]);
|
||||
headers.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break;
|
||||
|
||||
bufferSizeBytes += 4096;
|
||||
}
|
||||
|
||||
DWORD status = 0;
|
||||
DWORD statusSize = sizeof (status);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
|
||||
{
|
||||
statusCode = (int) status;
|
||||
|
||||
if (status == 301 || status == 302 || status == 303 || status == 307)
|
||||
{
|
||||
const String newLocation (headers["Location"]);
|
||||
|
||||
if (newLocation.isNotEmpty() && newLocation != address)
|
||||
{
|
||||
address = newLocation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (responseHeaders != nullptr)
|
||||
responseHeaders->addArray (headers);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
~WebInputStream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return request == 0; }
|
||||
bool isExhausted() { return finished; }
|
||||
int64 getPosition() { return position; }
|
||||
|
||||
int64 getTotalLength()
|
||||
{
|
||||
if (! isError())
|
||||
{
|
||||
DWORD index = 0, result = 0, size = sizeof (result);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
|
||||
return (int64) result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read (void* buffer, int bytesToRead)
|
||||
{
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
if (! (finished || isError()))
|
||||
{
|
||||
InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead);
|
||||
position += bytesRead;
|
||||
|
||||
if (bytesRead == 0)
|
||||
finished = true;
|
||||
}
|
||||
|
||||
return (int) bytesRead;
|
||||
}
|
||||
|
||||
bool setPosition (int64 wantedPos)
|
||||
{
|
||||
if (isError())
|
||||
return false;
|
||||
|
||||
if (wantedPos != position)
|
||||
{
|
||||
finished = false;
|
||||
position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
|
||||
|
||||
if (position == wantedPos)
|
||||
return true;
|
||||
|
||||
if (wantedPos < position)
|
||||
{
|
||||
close();
|
||||
position = 0;
|
||||
createConnection (0, 0);
|
||||
}
|
||||
|
||||
skipNextBytes (wantedPos - position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int statusCode;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
HINTERNET connection, request;
|
||||
String address, headers;
|
||||
MemoryBlock postData;
|
||||
int64 position;
|
||||
bool finished;
|
||||
const bool isPost;
|
||||
int timeOutMs;
|
||||
|
||||
void close()
|
||||
{
|
||||
if (request != 0)
|
||||
{
|
||||
InternetCloseHandle (request);
|
||||
request = 0;
|
||||
}
|
||||
|
||||
if (connection != 0)
|
||||
{
|
||||
InternetCloseHandle (connection);
|
||||
connection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
static HINTERNET sessionHandle = InternetOpen (_T("juce"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
|
||||
|
||||
close();
|
||||
|
||||
if (sessionHandle != 0)
|
||||
{
|
||||
// break up the url..
|
||||
const int fileNumChars = 65536;
|
||||
const int serverNumChars = 2048;
|
||||
const int usernameNumChars = 1024;
|
||||
const int passwordNumChars = 1024;
|
||||
HeapBlock<TCHAR> file (fileNumChars), server (serverNumChars),
|
||||
username (usernameNumChars), password (passwordNumChars);
|
||||
|
||||
URL_COMPONENTS uc = { 0 };
|
||||
uc.dwStructSize = sizeof (uc);
|
||||
uc.lpszUrlPath = file;
|
||||
uc.dwUrlPathLength = fileNumChars;
|
||||
uc.lpszHostName = server;
|
||||
uc.dwHostNameLength = serverNumChars;
|
||||
uc.lpszUserName = username;
|
||||
uc.dwUserNameLength = usernameNumChars;
|
||||
uc.lpszPassword = password;
|
||||
uc.dwPasswordLength = passwordNumChars;
|
||||
|
||||
if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc))
|
||||
openConnection (uc, sessionHandle, progressCallback, progressCallbackContext);
|
||||
}
|
||||
}
|
||||
|
||||
void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle,
|
||||
URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
int disable = 1;
|
||||
InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
|
||||
|
||||
if (timeOutMs == 0)
|
||||
timeOutMs = 30000;
|
||||
else if (timeOutMs < 0)
|
||||
timeOutMs = -1;
|
||||
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT);
|
||||
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT);
|
||||
|
||||
const bool isFtp = address.startsWithIgnoreCase ("ftp:");
|
||||
|
||||
connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
|
||||
uc.lpszUserName, uc.lpszPassword,
|
||||
isFtp ? (DWORD) INTERNET_SERVICE_FTP
|
||||
: (DWORD) INTERNET_SERVICE_HTTP,
|
||||
0, 0);
|
||||
if (connection != 0)
|
||||
{
|
||||
if (isFtp)
|
||||
request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
|
||||
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
|
||||
else
|
||||
openHTTPConnection (uc, progressCallback, progressCallbackContext);
|
||||
}
|
||||
}
|
||||
|
||||
void applyTimeout (HINTERNET sessionHandle, const DWORD option)
|
||||
{
|
||||
InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs));
|
||||
}
|
||||
|
||||
void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback,
|
||||
void* progressCallbackContext)
|
||||
{
|
||||
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
|
||||
|
||||
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES
|
||||
| INTERNET_FLAG_NO_AUTO_REDIRECT | SECURITY_SET_MASK;
|
||||
|
||||
if (address.startsWithIgnoreCase ("https:"))
|
||||
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
|
||||
// IE7 seems to automatically work out when it's https)
|
||||
|
||||
request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
|
||||
uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
|
||||
|
||||
if (request != 0)
|
||||
{
|
||||
setSecurityFlags();
|
||||
|
||||
INTERNET_BUFFERS buffers = { 0 };
|
||||
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
|
||||
buffers.lpcszHeader = headers.toWideCharPointer();
|
||||
buffers.dwHeadersLength = (DWORD) headers.length();
|
||||
buffers.dwBufferTotal = (DWORD) postData.getSize();
|
||||
|
||||
if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
|
||||
{
|
||||
int bytesSent = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const int bytesToDo = jmin (1024, (int) postData.getSize() - bytesSent);
|
||||
DWORD bytesDone = 0;
|
||||
|
||||
if (bytesToDo > 0
|
||||
&& ! InternetWriteFile (request,
|
||||
static_cast<const char*> (postData.getData()) + bytesSent,
|
||||
(DWORD) bytesToDo, &bytesDone))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
|
||||
{
|
||||
if (HttpEndRequest (request, 0, 0, 0))
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bytesSent += bytesDone;
|
||||
|
||||
if (progressCallback != nullptr
|
||||
&& ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize()))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void setSecurityFlags()
|
||||
{
|
||||
DWORD dwFlags = 0, dwBuffLen = sizeof (DWORD);
|
||||
InternetQueryOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffLen);
|
||||
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_SET_MASK;
|
||||
InternetSetOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct GetAdaptersInfoHelper
|
||||
{
|
||||
bool callGetAdaptersInfo()
|
||||
{
|
||||
DynamicLibrary dll ("iphlpapi.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, GetAdaptersInfo, getAdaptersInfo, DWORD, (PIP_ADAPTER_INFO, PULONG))
|
||||
|
||||
if (getAdaptersInfo == nullptr)
|
||||
return false;
|
||||
|
||||
adapterInfo.malloc (1);
|
||||
ULONG len = sizeof (IP_ADAPTER_INFO);
|
||||
|
||||
if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
|
||||
adapterInfo.malloc (len, 1);
|
||||
|
||||
return getAdaptersInfo (adapterInfo, &len) == NO_ERROR;
|
||||
}
|
||||
|
||||
HeapBlock<IP_ADAPTER_INFO> adapterInfo;
|
||||
};
|
||||
|
||||
namespace MACAddressHelpers
|
||||
{
|
||||
static void addAddress (Array<MACAddress>& result, const MACAddress& ma)
|
||||
{
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
|
||||
static void getViaGetAdaptersInfo (Array<MACAddress>& result)
|
||||
{
|
||||
GetAdaptersInfoHelper gah;
|
||||
|
||||
if (gah.callGetAdaptersInfo())
|
||||
{
|
||||
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||
if (adapter->AddressLength >= 6)
|
||||
addAddress (result, MACAddress (adapter->Address));
|
||||
}
|
||||
}
|
||||
|
||||
static void getViaNetBios (Array<MACAddress>& result)
|
||||
{
|
||||
DynamicLibrary dll ("netapi32.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
|
||||
|
||||
if (NetbiosCall != 0)
|
||||
{
|
||||
LANA_ENUM enums = { 0 };
|
||||
|
||||
{
|
||||
NCB ncb = { 0 };
|
||||
ncb.ncb_command = NCBENUM;
|
||||
ncb.ncb_buffer = (unsigned char*) &enums;
|
||||
ncb.ncb_length = sizeof (LANA_ENUM);
|
||||
NetbiosCall (&ncb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < enums.length; ++i)
|
||||
{
|
||||
NCB ncb2 = { 0 };
|
||||
ncb2.ncb_command = NCBRESET;
|
||||
ncb2.ncb_lana_num = enums.lana[i];
|
||||
|
||||
if (NetbiosCall (&ncb2) == 0)
|
||||
{
|
||||
NCB ncb = { 0 };
|
||||
memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
|
||||
ncb.ncb_command = NCBASTAT;
|
||||
ncb.ncb_lana_num = enums.lana[i];
|
||||
|
||||
struct ASTAT
|
||||
{
|
||||
ADAPTER_STATUS adapt;
|
||||
NAME_BUFFER NameBuff [30];
|
||||
};
|
||||
|
||||
ASTAT astat;
|
||||
zerostruct (astat);
|
||||
ncb.ncb_buffer = (unsigned char*) &astat;
|
||||
ncb.ncb_length = sizeof (ASTAT);
|
||||
|
||||
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
|
||||
addAddress (result, MACAddress (astat.adapt.adapter_address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
MACAddressHelpers::getViaGetAdaptersInfo (result);
|
||||
MACAddressHelpers::getViaNetBios (result);
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result)
|
||||
{
|
||||
result.addIfNotAlreadyThere (IPAddress::local());
|
||||
|
||||
GetAdaptersInfoHelper gah;
|
||||
|
||||
if (gah.callGetAdaptersInfo())
|
||||
{
|
||||
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||
{
|
||||
IPAddress ip (adapter->IpAddressList.IpAddress.String);
|
||||
|
||||
if (ip != IPAddress::any())
|
||||
result.addIfNotAlreadyThere (ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
DynamicLibrary dll ("MAPI32.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, MAPISendMail, mapiSendMail,
|
||||
ULONG, (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG))
|
||||
|
||||
if (mapiSendMail == nullptr)
|
||||
return false;
|
||||
|
||||
MapiMessage message = { 0 };
|
||||
message.lpszSubject = (LPSTR) emailSubject.toRawUTF8();
|
||||
message.lpszNoteText = (LPSTR) bodyText.toRawUTF8();
|
||||
|
||||
MapiRecipDesc recip = { 0 };
|
||||
recip.ulRecipClass = MAPI_TO;
|
||||
String targetEmailAddress_ (targetEmailAddress);
|
||||
if (targetEmailAddress_.isEmpty())
|
||||
targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
|
||||
recip.lpszName = (LPSTR) targetEmailAddress_.toRawUTF8();
|
||||
message.nRecipCount = 1;
|
||||
message.lpRecips = &recip;
|
||||
|
||||
HeapBlock <MapiFileDesc> files;
|
||||
files.calloc ((size_t) filesToAttach.size());
|
||||
|
||||
message.nFileCount = (ULONG) filesToAttach.size();
|
||||
message.lpFiles = files;
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
files[i].nPosition = (ULONG) -1;
|
||||
files[i].lpszPathName = (LPSTR) filesToAttach[i].toRawUTF8();
|
||||
}
|
||||
|
||||
return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
struct RegistryKeyWrapper
|
||||
{
|
||||
RegistryKeyWrapper (String name, const bool createForWriting, const DWORD wow64Flags)
|
||||
: key (0), wideCharValueName (nullptr)
|
||||
{
|
||||
HKEY rootKey = 0;
|
||||
|
||||
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) rootKey = HKEY_CURRENT_USER;
|
||||
else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) rootKey = HKEY_LOCAL_MACHINE;
|
||||
else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) rootKey = HKEY_CLASSES_ROOT;
|
||||
|
||||
if (rootKey != 0)
|
||||
{
|
||||
name = name.substring (name.indexOfChar ('\\') + 1);
|
||||
|
||||
const int lastSlash = name.lastIndexOfChar ('\\');
|
||||
valueName = name.substring (lastSlash + 1);
|
||||
wideCharValueName = valueName.toWideCharPointer();
|
||||
|
||||
name = name.substring (0, lastSlash);
|
||||
const wchar_t* const wideCharName = name.toWideCharPointer();
|
||||
DWORD result;
|
||||
|
||||
if (createForWriting)
|
||||
RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result);
|
||||
else
|
||||
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
|
||||
}
|
||||
}
|
||||
|
||||
~RegistryKeyWrapper()
|
||||
{
|
||||
if (key != 0)
|
||||
RegCloseKey (key);
|
||||
}
|
||||
|
||||
static bool setValue (const String& regValuePath, const DWORD type,
|
||||
const void* data, size_t dataSize, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, wow64Flags);
|
||||
|
||||
return key.key != 0
|
||||
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
|
||||
reinterpret_cast <const BYTE*> (data),
|
||||
(DWORD) dataSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key != 0)
|
||||
{
|
||||
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
DWORD type = REG_NONE;
|
||||
|
||||
const LONG err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type,
|
||||
(LPBYTE) result.getData(), &bufferSize);
|
||||
|
||||
if (err == ERROR_SUCCESS)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
if (err != ERROR_MORE_DATA)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return REG_NONE;
|
||||
}
|
||||
|
||||
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
|
||||
{
|
||||
MemoryBlock buffer;
|
||||
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
|
||||
{
|
||||
case REG_SZ: return static_cast <const WCHAR*> (buffer.getData());
|
||||
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
|
||||
default: break;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static bool keyExists (const String& regValuePath, const DWORD wow64Flags)
|
||||
{
|
||||
return RegistryKeyWrapper (regValuePath, false, wow64Flags).key != 0;
|
||||
}
|
||||
|
||||
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key == 0)
|
||||
return false;
|
||||
|
||||
unsigned char buffer [512];
|
||||
unsigned long bufferSize = sizeof (buffer);
|
||||
DWORD type = 0;
|
||||
|
||||
const LONG result = RegQueryValueEx (key.key, key.wideCharValueName,
|
||||
0, &type, buffer, &bufferSize);
|
||||
|
||||
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
|
||||
}
|
||||
|
||||
HKEY key;
|
||||
const wchar_t* wideCharValueName;
|
||||
String valueName;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
|
||||
};
|
||||
|
||||
uint32 JUCE_CALLTYPE WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, (DWORD) mode);
|
||||
}
|
||||
|
||||
String JUCE_CALLTYPE WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const String& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
|
||||
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()), mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint32 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint64 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize(), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::valueExists (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::valueExists (regValuePath, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::keyExists (regValuePath, (DWORD) mode);
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode);
|
||||
|
||||
if (key.key != 0)
|
||||
RegDeleteValue (key.key, key.wideCharValueName);
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);
|
||||
|
||||
if (key.key != 0)
|
||||
RegDeleteKey (key.key, key.wideCharValueName);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
const int iconResourceNumber,
|
||||
const bool registerForCurrentUserOnly,
|
||||
WoW64Mode mode)
|
||||
{
|
||||
const char* const root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
|
||||
: "HKEY_CLASSES_ROOT\\";
|
||||
const String key (root + symbolicDescription);
|
||||
|
||||
return setValue (root + fileExtension + "\\", symbolicDescription, mode)
|
||||
&& setValue (key + "\\", fullDescription, mode)
|
||||
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"", mode)
|
||||
&& (iconResourceNumber == 0
|
||||
|| setValue (key + "\\DefaultIcon\\",
|
||||
targetExecutable.getFullPathName() + "," + String (iconResourceNumber)));
|
||||
}
|
||||
|
||||
// These methods are deprecated:
|
||||
String WindowsRegistry::getValueWow64 (const String& p, const String& defVal) { return getValue (p, defVal, WoW64_64bit); }
|
||||
bool WindowsRegistry::valueExistsWow64 (const String& p) { return valueExists (p, WoW64_64bit); }
|
||||
bool WindowsRegistry::keyExistsWow64 (const String& p) { return keyExists (p, WoW64_64bit); }
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
OutputDebugString ((text + "\n").toWideCharPointer());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#ifdef JUCE_DLL_BUILD
|
||||
JUCE_API void* juceDLL_malloc (size_t sz) { return std::malloc (sz); }
|
||||
JUCE_API void juceDLL_free (void* block) { std::free (block); }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
|
||||
// CPU info functions using intrinsics...
|
||||
|
||||
#pragma intrinsic (__cpuid)
|
||||
#pragma intrinsic (__rdtsc)
|
||||
|
||||
static void callCPUID (int result[4], int infoType)
|
||||
{
|
||||
__cpuid (result, infoType);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void callCPUID (int result[4], int infoType)
|
||||
{
|
||||
#if ! JUCE_MINGW
|
||||
__try
|
||||
#endif
|
||||
{
|
||||
#if JUCE_GCC
|
||||
__asm__ __volatile__ ("cpuid" : "=a" (result[0]), "=b" (result[1]), "=c" (result[2]),"=d" (result[3]) : "a" (infoType));
|
||||
#else
|
||||
__asm
|
||||
{
|
||||
mov esi, result
|
||||
mov eax, infoType
|
||||
xor ecx, ecx
|
||||
cpuid
|
||||
mov dword ptr [esi + 0], eax
|
||||
mov dword ptr [esi + 4], ebx
|
||||
mov dword ptr [esi + 8], ecx
|
||||
mov dword ptr [esi + 12], edx
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if ! JUCE_MINGW
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
int info[4] = { 0 };
|
||||
callCPUID (info, 0);
|
||||
|
||||
char v [12];
|
||||
memcpy (v, info + 1, 4);
|
||||
memcpy (v + 4, info + 3, 4);
|
||||
memcpy (v + 8, info + 2, 4);
|
||||
|
||||
return String (v, 12);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
int info[4] = { 0 };
|
||||
callCPUID (info, 1);
|
||||
|
||||
// NB: IsProcessorFeaturePresent doesn't work on XP
|
||||
hasMMX = (info[3] & (1 << 23)) != 0;
|
||||
hasSSE = (info[3] & (1 << 25)) != 0;
|
||||
hasSSE2 = (info[3] & (1 << 26)) != 0;
|
||||
hasSSE3 = (info[2] & (1 << 0)) != 0;
|
||||
has3DNow = (info[1] & (1 << 31)) != 0;
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo (&systemInfo);
|
||||
numCpus = (int) systemInfo.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
|
||||
struct DebugFlagsInitialiser
|
||||
{
|
||||
DebugFlagsInitialiser()
|
||||
{
|
||||
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
}
|
||||
};
|
||||
|
||||
static DebugFlagsInitialiser debugFlagsInitialiser;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
|
||||
{
|
||||
OSVERSIONINFOEX info;
|
||||
zerostruct (info);
|
||||
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
|
||||
|
||||
if (target >= SystemStats::WinVista)
|
||||
{
|
||||
info.dwMajorVersion = 6;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case SystemStats::WinVista: break;
|
||||
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
|
||||
case SystemStats::Windows8_0: info.dwMinorVersion = 2; break;
|
||||
case SystemStats::Windows8_1: info.dwMinorVersion = 3; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info.dwMajorVersion = 5;
|
||||
info.dwMinorVersion = target >= SystemStats::WinXP ? 1 : 0;
|
||||
}
|
||||
|
||||
DWORDLONG mask = 0;
|
||||
|
||||
VER_SET_CONDITION (mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION (mask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION (mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION (mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
|
||||
|
||||
return VerifyVersionInfo (&info,
|
||||
VER_MAJORVERSION | VER_MINORVERSION
|
||||
| VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
|
||||
mask) != FALSE;
|
||||
}
|
||||
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
const SystemStats::OperatingSystemType types[]
|
||||
= { Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (types); ++i)
|
||||
if (isWindowsVersionOrLater (types[i]))
|
||||
return types[i];
|
||||
|
||||
jassertfalse; // need to support whatever new version is running!
|
||||
return UnknownOS;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
const char* name = "Unknown OS";
|
||||
|
||||
switch (getOperatingSystemType())
|
||||
{
|
||||
case Windows8_1: name = "Windows 8.1"; break;
|
||||
case Windows8_0: name = "Windows 8.0"; break;
|
||||
case Windows7: name = "Windows 7"; break;
|
||||
case WinVista: name = "Windows Vista"; break;
|
||||
case WinXP: name = "Windows XP"; break;
|
||||
case Win2000: name = "Windows 2000"; break;
|
||||
default: jassertfalse; break; // !! new type of OS?
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process
|
||||
= (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandleA ("kernel32"), "IsWow64Process");
|
||||
|
||||
BOOL isWow64 = FALSE;
|
||||
|
||||
return fnIsWow64Process != nullptr
|
||||
&& fnIsWow64Process (GetCurrentProcess(), &isWow64)
|
||||
&& isWow64 != FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
MEMORYSTATUSEX mem;
|
||||
mem.dwLength = sizeof (mem);
|
||||
GlobalMemoryStatusEx (&mem);
|
||||
return (int) (mem.ullTotalPhys / (1024 * 1024)) + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
||||
{
|
||||
DWORD len = GetEnvironmentVariableW (name.toWideCharPointer(), nullptr, 0);
|
||||
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
|
||||
return String (defaultValue);
|
||||
|
||||
HeapBlock<WCHAR> buffer (len);
|
||||
len = GetEnvironmentVariableW (name.toWideCharPointer(), buffer, len);
|
||||
|
||||
return String (CharPointer_wchar_t (buffer),
|
||||
CharPointer_wchar_t (buffer + len));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return (uint32) timeGetTime();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class HiResCounterHandler
|
||||
{
|
||||
public:
|
||||
HiResCounterHandler()
|
||||
: hiResTicksOffset (0)
|
||||
{
|
||||
// This macro allows you to override the default timer-period
|
||||
// used on Windows. By default this is set to 1, because that has
|
||||
// always been the value used in JUCE apps, and changing it could
|
||||
// affect the behaviour of existing code, but you may wish to make
|
||||
// it larger (or set it to 0 to use the system default) to make your
|
||||
// app less demanding on the CPU.
|
||||
// For more info, see win32 documentation about the timeBeginPeriod
|
||||
// function.
|
||||
#ifndef JUCE_WIN32_TIMER_PERIOD
|
||||
#define JUCE_WIN32_TIMER_PERIOD 1
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32_TIMER_PERIOD > 0
|
||||
const MMRESULT res = timeBeginPeriod (JUCE_WIN32_TIMER_PERIOD);
|
||||
(void) res;
|
||||
jassert (res == TIMERR_NOERROR);
|
||||
#endif
|
||||
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency (&f);
|
||||
hiResTicksPerSecond = f.QuadPart;
|
||||
hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
|
||||
}
|
||||
|
||||
inline int64 getHighResolutionTicks() noexcept
|
||||
{
|
||||
LARGE_INTEGER ticks;
|
||||
QueryPerformanceCounter (&ticks);
|
||||
|
||||
const int64 mainCounterAsHiResTicks = (juce_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000;
|
||||
const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
|
||||
|
||||
// fix for a very obscure PCI hardware bug that can make the counter
|
||||
// sometimes jump forwards by a few seconds..
|
||||
const int64 offsetDrift = abs64 (newOffset - hiResTicksOffset);
|
||||
|
||||
if (offsetDrift > (hiResTicksPerSecond >> 1))
|
||||
hiResTicksOffset = newOffset;
|
||||
|
||||
return ticks.QuadPart + hiResTicksOffset;
|
||||
}
|
||||
|
||||
inline double getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return getHighResolutionTicks() * hiResTicksScaleFactor;
|
||||
}
|
||||
|
||||
int64 hiResTicksPerSecond, hiResTicksOffset;
|
||||
double hiResTicksScaleFactor;
|
||||
};
|
||||
|
||||
static HiResCounterHandler hiResCounterHandler;
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.hiResTicksPerSecond; }
|
||||
int64 Time::getHighResolutionTicks() noexcept { return hiResCounterHandler.getHighResolutionTicks(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||
|
||||
//==============================================================================
|
||||
static int64 juce_getClockCycleCounter() noexcept
|
||||
{
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
// MS intrinsics version...
|
||||
return (int64) __rdtsc();
|
||||
|
||||
#elif JUCE_GCC
|
||||
// GNU inline asm version...
|
||||
unsigned int hi = 0, lo = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"xor %%eax, %%eax \n\
|
||||
xor %%edx, %%edx \n\
|
||||
rdtsc \n\
|
||||
movl %%eax, %[lo] \n\
|
||||
movl %%edx, %[hi]"
|
||||
:
|
||||
: [hi] "m" (hi),
|
||||
[lo] "m" (lo)
|
||||
: "cc", "eax", "ebx", "ecx", "edx", "memory");
|
||||
|
||||
return (int64) ((((uint64) hi) << 32) | lo);
|
||||
#else
|
||||
// MSVC inline asm version...
|
||||
unsigned int hi = 0, lo = 0;
|
||||
|
||||
__asm
|
||||
{
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
rdtsc
|
||||
mov lo, eax
|
||||
mov hi, edx
|
||||
}
|
||||
|
||||
return (int64) ((((uint64) hi) << 32) | lo);
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegaherz()
|
||||
{
|
||||
const int64 cycles = juce_getClockCycleCounter();
|
||||
const uint32 millis = Time::getMillisecondCounter();
|
||||
int lastResult = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int n = 1000000;
|
||||
while (--n > 0) {}
|
||||
|
||||
const uint32 millisElapsed = Time::getMillisecondCounter() - millis;
|
||||
const int64 cyclesNow = juce_getClockCycleCounter();
|
||||
|
||||
if (millisElapsed > 80)
|
||||
{
|
||||
const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
|
||||
|
||||
if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
|
||||
return newResult;
|
||||
|
||||
lastResult = newResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
st.wDayOfWeek = 0;
|
||||
st.wYear = (WORD) getYear();
|
||||
st.wMonth = (WORD) (getMonth() + 1);
|
||||
st.wDay = (WORD) getDayOfMonth();
|
||||
st.wHour = (WORD) getHours();
|
||||
st.wMinute = (WORD) getMinutes();
|
||||
st.wSecond = (WORD) getSeconds();
|
||||
st.wMilliseconds = (WORD) (millisSinceEpoch % 1000);
|
||||
|
||||
// do this twice because of daylight saving conversion problems - the
|
||||
// first one sets it up, the second one kicks it in.
|
||||
return SetLocalTime (&st) != 0
|
||||
&& SetLocalTime (&st) != 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo (&systemInfo);
|
||||
|
||||
return (int) systemInfo.dwPageSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
TCHAR text [256] = { 0 };
|
||||
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||
GetUserName (text, &len);
|
||||
return String (text, len);
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||
GetComputerName (text, &len);
|
||||
return String (text, len);
|
||||
}
|
||||
|
||||
static String getLocaleValue (LCID locale, LCTYPE key, const char* defaultValue)
|
||||
{
|
||||
TCHAR buffer [256] = { 0 };
|
||||
if (GetLocaleInfo (locale, key, buffer, 255) > 0)
|
||||
return buffer;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, "en"); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, "US"); }
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
DynamicLibrary dll ("kernel32.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
|
||||
|
||||
if (getUserDefaultUILanguage == nullptr)
|
||||
return "en";
|
||||
|
||||
const DWORD langID = MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT);
|
||||
|
||||
String mainLang (getLocaleValue (langID, LOCALE_SISO639LANGNAME, "en"));
|
||||
String region (getLocaleValue (langID, LOCALE_SISO3166CTRYNAME, nullptr));
|
||||
|
||||
if (region.isNotEmpty())
|
||||
mainLang << '-' << region;
|
||||
|
||||
return mainLang;
|
||||
}
|
||||
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
HWND juce_messageWindowHandle = 0; // (this is used by other parts of the codebase)
|
||||
|
||||
void* getUser32Function (const char* functionName)
|
||||
{
|
||||
HMODULE module = GetModuleHandleA ("user32.dll");
|
||||
jassert (module != 0);
|
||||
return (void*) GetProcAddress (module, functionName);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_USE_MSVC_INTRINSICS
|
||||
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
|
||||
// older ones we have to actually call the ops as win32 functions..
|
||||
long juce_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
|
||||
long juce_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); }
|
||||
long juce_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); }
|
||||
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); }
|
||||
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
|
||||
|
||||
__int64 juce_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept
|
||||
{
|
||||
jassertfalse; // This operation isn't available in old MS compiler versions!
|
||||
|
||||
__int64 oldValue = *value;
|
||||
if (oldValue == valueToCompare)
|
||||
*value = newValue;
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
CriticalSection::CriticalSection() noexcept
|
||||
{
|
||||
// (just to check the MS haven't changed this structure and broken things...)
|
||||
#if JUCE_VC7_OR_EARLIER
|
||||
static_jassert (sizeof (CRITICAL_SECTION) <= 24);
|
||||
#else
|
||||
static_jassert (sizeof (CRITICAL_SECTION) <= sizeof (lock));
|
||||
#endif
|
||||
|
||||
InitializeCriticalSection ((CRITICAL_SECTION*) lock);
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection() noexcept { DeleteCriticalSection ((CRITICAL_SECTION*) lock); }
|
||||
void CriticalSection::enter() const noexcept { EnterCriticalSection ((CRITICAL_SECTION*) lock); }
|
||||
bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSection ((CRITICAL_SECTION*) lock) != FALSE; }
|
||||
void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) lock); }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
WaitableEvent::WaitableEvent (const bool manualReset) noexcept
|
||||
: handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {}
|
||||
|
||||
WaitableEvent::~WaitableEvent() noexcept { CloseHandle (handle); }
|
||||
|
||||
void WaitableEvent::signal() const noexcept { SetEvent (handle); }
|
||||
void WaitableEvent::reset() const noexcept { ResetEvent (handle); }
|
||||
|
||||
bool WaitableEvent::wait (const int timeOutMs) const noexcept
|
||||
{
|
||||
return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JUCE_API juce_threadEntryPoint (void*);
|
||||
|
||||
static unsigned int __stdcall threadEntryProc (void* userData)
|
||||
{
|
||||
if (juce_messageWindowHandle != 0)
|
||||
AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0),
|
||||
GetCurrentThreadId(), TRUE);
|
||||
|
||||
juce_threadEntryPoint (userData);
|
||||
|
||||
_endthreadex (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::launchThread()
|
||||
{
|
||||
unsigned int newThreadId;
|
||||
threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId);
|
||||
threadId = (ThreadID) newThreadId;
|
||||
}
|
||||
|
||||
void Thread::closeThreadHandle()
|
||||
{
|
||||
CloseHandle ((HANDLE) threadHandle);
|
||||
threadId = 0;
|
||||
threadHandle = 0;
|
||||
}
|
||||
|
||||
void Thread::killThread()
|
||||
{
|
||||
if (threadHandle != 0)
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
OutputDebugStringA ("** Warning - Forced thread termination **\n");
|
||||
#endif
|
||||
TerminateThread (threadHandle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Thread::setCurrentThreadName (const String& name)
|
||||
{
|
||||
#if JUCE_DEBUG && JUCE_MSVC
|
||||
struct
|
||||
{
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
} info;
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name.toUTF8();
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
|
||||
}
|
||||
__except (EXCEPTION_CONTINUE_EXECUTION)
|
||||
{}
|
||||
#else
|
||||
(void) name;
|
||||
#endif
|
||||
}
|
||||
|
||||
Thread::ThreadID JUCE_CALLTYPE Thread::getCurrentThreadId()
|
||||
{
|
||||
return (ThreadID) (pointer_sized_int) GetCurrentThreadId();
|
||||
}
|
||||
|
||||
bool Thread::setThreadPriority (void* handle, int priority)
|
||||
{
|
||||
int pri = THREAD_PRIORITY_TIME_CRITICAL;
|
||||
|
||||
if (priority < 1) pri = THREAD_PRIORITY_IDLE;
|
||||
else if (priority < 2) pri = THREAD_PRIORITY_LOWEST;
|
||||
else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL;
|
||||
else if (priority < 7) pri = THREAD_PRIORITY_NORMAL;
|
||||
else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||
else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST;
|
||||
|
||||
if (handle == 0)
|
||||
handle = GetCurrentThread();
|
||||
|
||||
return SetThreadPriority (handle, pri) != FALSE;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMask)
|
||||
{
|
||||
SetThreadAffinityMask (GetCurrentThread(), affinityMask);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct SleepEvent
|
||||
{
|
||||
SleepEvent() noexcept
|
||||
: handle (CreateEvent (nullptr, FALSE, FALSE,
|
||||
#if JUCE_DEBUG
|
||||
_T("JUCE Sleep Event")))
|
||||
#else
|
||||
nullptr))
|
||||
#endif
|
||||
{}
|
||||
|
||||
~SleepEvent() noexcept
|
||||
{
|
||||
CloseHandle (handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
static SleepEvent sleepEvent;
|
||||
|
||||
void JUCE_CALLTYPE Thread::sleep (const int millisecs)
|
||||
{
|
||||
jassert (millisecs >= 0);
|
||||
|
||||
if (millisecs >= 10 || sleepEvent.handle == 0)
|
||||
Sleep ((DWORD) millisecs);
|
||||
else
|
||||
// unlike Sleep() this is guaranteed to return to the current thread after
|
||||
// the time expires, so we'll use this for short waits, which are more likely
|
||||
// to need to be accurate
|
||||
WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs);
|
||||
}
|
||||
|
||||
void Thread::yield()
|
||||
{
|
||||
Sleep (0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static int lastProcessPriority = -1;
|
||||
|
||||
// called when the app gains focus because Windows does weird things to process priority
|
||||
// when you swap apps, and this forces an update when the app is brought to the front.
|
||||
void juce_repeatLastProcessPriority()
|
||||
{
|
||||
if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..)
|
||||
{
|
||||
DWORD p;
|
||||
|
||||
switch (lastProcessPriority)
|
||||
{
|
||||
case Process::LowPriority: p = IDLE_PRIORITY_CLASS; break;
|
||||
case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break;
|
||||
case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break;
|
||||
case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break;
|
||||
default: jassertfalse; return; // bad priority value
|
||||
}
|
||||
|
||||
SetPriorityClass (GetCurrentProcess(), p);
|
||||
}
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
if (lastProcessPriority != (int) prior)
|
||||
{
|
||||
lastProcessPriority = (int) prior;
|
||||
juce_repeatLastProcessPriority();
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||
{
|
||||
return IsDebuggerPresent() != FALSE;
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||
{
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
static void* currentModuleHandle = nullptr;
|
||||
|
||||
void* JUCE_CALLTYPE Process::getCurrentModuleInstanceHandle() noexcept
|
||||
{
|
||||
if (currentModuleHandle == nullptr)
|
||||
currentModuleHandle = GetModuleHandleA (nullptr);
|
||||
|
||||
return currentModuleHandle;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept
|
||||
{
|
||||
currentModuleHandle = newHandle;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Process::raisePrivilege()
|
||||
{
|
||||
jassertfalse; // xxx not implemented
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Process::lowerPrivilege()
|
||||
{
|
||||
jassertfalse; // xxx not implemented
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Process::terminate()
|
||||
{
|
||||
#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
|
||||
// bullet in the head in case there's a problem shutting down..
|
||||
ExitProcess (1);
|
||||
}
|
||||
|
||||
bool juce_isRunningInWine()
|
||||
{
|
||||
HMODULE ntdll = GetModuleHandleA ("ntdll");
|
||||
return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool DynamicLibrary::open (const String& name)
|
||||
{
|
||||
close();
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
handle = LoadLibrary (name.toWideCharPointer());
|
||||
}
|
||||
JUCE_CATCH_ALL
|
||||
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
void DynamicLibrary::close()
|
||||
{
|
||||
JUCE_TRY
|
||||
{
|
||||
if (handle != nullptr)
|
||||
{
|
||||
FreeLibrary ((HMODULE) handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
JUCE_CATCH_ALL
|
||||
}
|
||||
|
||||
void* DynamicLibrary::getFunction (const String& functionName) noexcept
|
||||
{
|
||||
return handle != nullptr ? (void*) GetProcAddress ((HMODULE) handle, functionName.toUTF8()) // (void* cast is required for mingw)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class InterProcessLock::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (String name, const int timeOutMillisecs)
|
||||
: handle (0), refCount (1)
|
||||
{
|
||||
name = name.replaceCharacter ('\\', '/');
|
||||
handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer());
|
||||
|
||||
// Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to
|
||||
// a local one. (A local one also sometimes fails on other machines so neither type appears to be
|
||||
// universally reliable)
|
||||
if (handle == 0)
|
||||
handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer());
|
||||
|
||||
if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
if (timeOutMillisecs == 0)
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
default:
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (handle != 0)
|
||||
{
|
||||
ReleaseMutex (handle);
|
||||
CloseHandle (handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE handle;
|
||||
int refCount;
|
||||
};
|
||||
|
||||
InterProcessLock::InterProcessLock (const String& name_)
|
||||
: name (name_)
|
||||
{
|
||||
}
|
||||
|
||||
InterProcessLock::~InterProcessLock()
|
||||
{
|
||||
}
|
||||
|
||||
bool InterProcessLock::enter (const int timeOutMillisecs)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (pimpl == nullptr)
|
||||
{
|
||||
pimpl = new Pimpl (name, timeOutMillisecs);
|
||||
|
||||
if (pimpl->handle == 0)
|
||||
pimpl = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pimpl->refCount++;
|
||||
}
|
||||
|
||||
return pimpl != nullptr;
|
||||
}
|
||||
|
||||
void InterProcessLock::exit()
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
// Trying to release the lock too many times!
|
||||
jassert (pimpl != nullptr);
|
||||
|
||||
if (pimpl != nullptr && --(pimpl->refCount) == 0)
|
||||
pimpl = nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ChildProcess::ActiveProcess
|
||||
{
|
||||
public:
|
||||
ActiveProcess (const String& command, int streamFlags)
|
||||
: ok (false), readPipe (0), writePipe (0)
|
||||
{
|
||||
SECURITY_ATTRIBUTES securityAtts = { 0 };
|
||||
securityAtts.nLength = sizeof (securityAtts);
|
||||
securityAtts.bInheritHandle = TRUE;
|
||||
|
||||
if (CreatePipe (&readPipe, &writePipe, &securityAtts, 0)
|
||||
&& SetHandleInformation (readPipe, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
STARTUPINFOW startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof (startupInfo);
|
||||
|
||||
startupInfo.hStdOutput = (streamFlags | wantStdOut) != 0 ? writePipe : 0;
|
||||
startupInfo.hStdError = (streamFlags | wantStdErr) != 0 ? writePipe : 0;
|
||||
startupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
ok = CreateProcess (nullptr, const_cast <LPWSTR> (command.toWideCharPointer()),
|
||||
nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||
nullptr, nullptr, &startupInfo, &processInfo) != FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
~ActiveProcess()
|
||||
{
|
||||
if (ok)
|
||||
{
|
||||
CloseHandle (processInfo.hThread);
|
||||
CloseHandle (processInfo.hProcess);
|
||||
}
|
||||
|
||||
if (readPipe != 0)
|
||||
CloseHandle (readPipe);
|
||||
|
||||
if (writePipe != 0)
|
||||
CloseHandle (writePipe);
|
||||
}
|
||||
|
||||
bool isRunning() const noexcept
|
||||
{
|
||||
return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
int read (void* dest, int numNeeded) const noexcept
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
while (ok && numNeeded > 0)
|
||||
{
|
||||
DWORD available = 0;
|
||||
|
||||
if (! PeekNamedPipe ((HANDLE) readPipe, nullptr, 0, nullptr, &available, nullptr))
|
||||
break;
|
||||
|
||||
const int numToDo = jmin ((int) available, numNeeded);
|
||||
|
||||
if (available == 0)
|
||||
{
|
||||
if (! isRunning())
|
||||
break;
|
||||
|
||||
Thread::yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD numRead = 0;
|
||||
if (! ReadFile ((HANDLE) readPipe, dest, numToDo, &numRead, nullptr))
|
||||
break;
|
||||
|
||||
total += numRead;
|
||||
dest = addBytesToPointer (dest, numRead);
|
||||
numNeeded -= numRead;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool killProcess() const noexcept
|
||||
{
|
||||
return TerminateProcess (processInfo.hProcess, 0) != FALSE;
|
||||
}
|
||||
|
||||
uint32 getExitCode() const noexcept
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess (processInfo.hProcess, &exitCode);
|
||||
return (uint32) exitCode;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
|
||||
private:
|
||||
HANDLE readPipe, writePipe;
|
||||
PROCESS_INFORMATION processInfo;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess)
|
||||
};
|
||||
|
||||
bool ChildProcess::start (const String& command, int streamFlags)
|
||||
{
|
||||
activeProcess = new ActiveProcess (command, streamFlags);
|
||||
|
||||
if (! activeProcess->ok)
|
||||
activeProcess = nullptr;
|
||||
|
||||
return activeProcess != nullptr;
|
||||
}
|
||||
|
||||
bool ChildProcess::start (const StringArray& args, int streamFlags)
|
||||
{
|
||||
String escaped;
|
||||
|
||||
for (int i = 0; i < args.size(); ++i)
|
||||
{
|
||||
String arg (args[i]);
|
||||
|
||||
// If there are spaces, surround it with quotes. If there are quotes,
|
||||
// replace them with \" so that CommandLineToArgv will correctly parse them.
|
||||
if (arg.containsAnyOf ("\" "))
|
||||
arg = arg.replace ("\"", "\\\"").quoted();
|
||||
|
||||
escaped << arg << ' ';
|
||||
}
|
||||
|
||||
return start (escaped.trim(), streamFlags);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct HighResolutionTimer::Pimpl
|
||||
{
|
||||
Pimpl (HighResolutionTimer& t) noexcept : owner (t), periodMs (0)
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
jassert (periodMs == 0);
|
||||
}
|
||||
|
||||
void start (int newPeriod)
|
||||
{
|
||||
if (newPeriod != periodMs)
|
||||
{
|
||||
stop();
|
||||
periodMs = newPeriod;
|
||||
|
||||
TIMECAPS tc;
|
||||
if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR)
|
||||
{
|
||||
const int actualPeriod = jlimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod);
|
||||
|
||||
timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this,
|
||||
TIME_PERIODIC | TIME_CALLBACK_FUNCTION | 0x100 /*TIME_KILL_SYNCHRONOUS*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
periodMs = 0;
|
||||
timeKillEvent (timerID);
|
||||
}
|
||||
|
||||
HighResolutionTimer& owner;
|
||||
int periodMs;
|
||||
|
||||
private:
|
||||
unsigned int timerID;
|
||||
|
||||
static void __stdcall callbackFunction (UINT, UINT, DWORD_PTR userInfo, DWORD_PTR, DWORD_PTR)
|
||||
{
|
||||
if (Pimpl* const timer = reinterpret_cast<Pimpl*> (userInfo))
|
||||
if (timer->periodMs != 0)
|
||||
timer->owner.hiResTimerCallback();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
Reference in New Issue
Block a user