Ejemplo n.º 1
0
PsychError SCREENRect(void)  
{
	
	PsychWindowRecordType *windowRecord;
	int screenNumber;
	PsychRectType rect; 
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(1));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.   
	PsychErrorExit(PsychCapNumOutputArgs(1));		//The maximum number of outputs

	if(PsychIsScreenNumberArg(1)){
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
		PsychGetScreenRect(screenNumber, rect);
		PsychCopyOutRectArg(1, FALSE, rect);
	}else if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
        PsychOSProcessEvents(windowRecord, 0);		
        PsychCopyOutRectArg(1,FALSE, windowRecord->clientrect);
	}else
		PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");
    
	return(PsychError_none);
}
Ejemplo n.º 2
0
PsychError SCREENPixelSize(void) 
{
    int 			screenNumber;
    double 			depth;
    PsychWindowRecordType	*windowRecord; 
    
    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    //get specified screen number.
    if(PsychIsScreenNumberArg(1)){    
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        depth=(double)PsychGetScreenDepthValue(screenNumber);
    }else if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1,TRUE,&windowRecord);
        depth=(double)windowRecord->depth;
    }else
        PsychErrorExit(PsychError_invalidNumdex);
        
    //Allocate a return matrix and load it with the depth values.  
    PsychCopyOutDoubleArg(1, FALSE, depth);
    
    return(PsychError_none);	
}
Ejemplo n.º 3
0
PsychError SCREENWindowSize(void)
{

    PsychWindowRecordType *windowRecord;
    int screenNumber;
    PsychRectType rect;
    double	rectWidth, rectHeight;

    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()) {
        PsychGiveHelp();
        return(PsychError_none);
    };

    //check for superfluous arguments
    PsychErrorExit(PsychCapNumInputArgs(1));		//The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.
    PsychErrorExit(PsychCapNumOutputArgs(2));		//The maximum number of outputs

    if(PsychIsScreenNumberArg(1)) {
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        PsychGetScreenRect(screenNumber, rect);
        rectWidth=PsychGetWidthFromRect(rect);
        rectHeight=PsychGetHeightFromRect(rect);
        PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
        PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
    } else if(PsychIsWindowIndexArg(1)) {
        PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
        PsychOSProcessEvents(windowRecord, 0);

        rectWidth=PsychGetWidthFromRect(windowRecord->rect);
        rectHeight=PsychGetHeightFromRect(windowRecord->rect);

        if (windowRecord->specialflags & kPsychHalfWidthWindow) {
            // Special case for stereo: Only half the real window width:
            rectWidth = rectWidth / 2;
        }

        if (windowRecord->specialflags & kPsychHalfHeightWindow) {
            // Special case for stereo: Only half the real window width:
            rectHeight = rectHeight / 2;
        }

        PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
        PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
    } else
        PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

    return(PsychError_none);
}
Ejemplo n.º 4
0
PsychError SCREENWindowSize(void)  
{
	PsychWindowRecordType *windowRecord;
	int screenNumber;
	double	rectWidth, rectHeight;
    long fbWidth, fbHeight;
    int realFBSize = 0;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(2));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.   
	PsychErrorExit(PsychCapNumOutputArgs(2));		//The maximum number of outputs

    // Get optional 'realFBSize' flag: Defaults to zero.
    PsychCopyInIntegerArg(2, FALSE, &realFBSize);

	if(PsychIsScreenNumberArg(1)){
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        if (realFBSize) {
            // Physical size in pixels:
            PsychGetScreenPixelSize(screenNumber, &fbWidth, &fbHeight);
        }
        else {
            // Logical size in points:
            PsychGetScreenSize(screenNumber, &fbWidth, &fbHeight);
        }
		PsychCopyOutDoubleArg(1, kPsychArgOptional, fbWidth);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, fbHeight);
	}else if(PsychIsWindowIndexArg(1)){
		PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
		PsychOSProcessEvents(windowRecord, 0);

		rectWidth=PsychGetWidthFromRect((realFBSize) ? windowRecord->rect : windowRecord->clientrect);
		rectHeight=PsychGetHeightFromRect((realFBSize) ? windowRecord->rect : windowRecord->clientrect);

		PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
	}else
		PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

	return(PsychError_none);
}
Ejemplo n.º 5
0
PsychError SCREENGlobalRect(void)  
{	
	int						screenNumber;
	PsychWindowRecordType	*windowRecord;
	PsychRectType			rect; 
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(1));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		 
	PsychErrorExit(PsychCapNumOutputArgs(1));			

	if(PsychIsScreenNumberArg(1)) {
		// Real screen id: Get screens global rect and return it:
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
		PsychGetGlobalScreenRect(screenNumber, rect);
		PsychCopyOutRectArg(1, FALSE, rect);
	}
	else if(PsychIsWindowIndexArg(1)) {
		// Window:
		PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);

		//  Onscreen?
		if (PsychIsOnscreenWindow(windowRecord)) {
			PsychCopyOutRectArg(1, FALSE, windowRecord->globalrect);
		}
		else {
			PsychCopyOutRectArg(1, FALSE, windowRecord->rect);
		}
	}
	else PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

	return(PsychError_none);
}
PsychError SCREENGetMouseHelper(void) 
{

    const char *valuatorInfo[]={"label", "min", "max", "resolution", "mode", "sourceID"};
    int numValuatorStructFieldNames = 6;
    int numIValuators = 0;
    PsychGenericScriptType *valuatorStruct = NULL;

#if PSYCH_SYSTEM == PSYCH_OSX
	Point		mouseXY;
	UInt32		buttonState;
	double		*buttonArray;
	int		numButtons, i;
	psych_bool	doButtonArray;
	PsychWindowRecordType *windowRecord;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(3));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(6));  //The maximum number of outputs
	
	//Buttons.  
	// The only way I know to detect the  number number of mouse buttons is directly via HID.  The device reports
	//that information but OS X seems to ignore it above the level of the HID driver, that is, no OS X API above the HID driver
	//exposes it.  So GetMouse.m function calls PsychHID detect the number of buttons and then passes that value to GetMouseHelper 
	//which returns that number of button values in a vector.      
	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);
	if(numButtons > 32)
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must not exceed 32");

	// Special codes -10 to -15? --> Console keyboard queries:
	if(numButtons <= -10 && numButtons >= -15) {
		ConsoleInputHelper((int) numButtons);
		return(PsychError_none);
	}

	if(numButtons < 1) 
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must exceed 1");

	doButtonArray=PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);
	if(doButtonArray){
		buttonState=GetCurrentButtonState();
		for(i=0;i<numButtons;i++)
			buttonArray[i]=(double)(buttonState & (1<<i));
	}
			
	// Get cursor position:
#ifndef __LP64__
    // 32-Bit Carbon version:
	GetGlobalMouse(&mouseXY);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)mouseXY.h);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double)mouseXY.v);
#else
    // 64-Bit HIToolbox version (OSX 10.5 and later):
    HIPoint outPoint;
    HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &outPoint);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) outPoint.x);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) outPoint.y);
#endif
	// Return optional keyboard input focus status:
	if (numButtons > 0) {
		// Window provided?
        // We only have the function GetUserFocusWindow on 32-Bit Carbon.
        // We have a drop-in replacement in OSX/PsychCocoaGlue.c for 64-Bit Cocoa.
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetUserFocusWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else
        {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}
	}

	// Return optional valuator values: Unimplemented on OS/X. Just return an empty matrix.
	// The buttonArray is just a dummy assignment without any meaning.
	PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
	static unsigned char disabledKeys[256];
	static unsigned char firsttime = 1;
	int keysdown, i, priorityLevel;
	unsigned char keyState[256];
	double* buttonArray;
	double numButtons, timestamp;
	PsychNativeBooleanType* buttonStates;
	POINT		point;
	HANDLE	   currentProcess;
	DWORD   oldPriority = NORMAL_PRIORITY_CLASS;
    const  DWORD   realtime_class = REALTIME_PRIORITY_CLASS;
	PsychWindowRecordType *windowRecord;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	// Retrieve optional number of mouse buttons:
	numButtons = 0;
	PsychCopyInDoubleArg(1, FALSE, &numButtons);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
		// GetMouse-Mode: Return mouse button states and mouse cursor position:

		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)3, (int)1, &buttonArray);
		// Query and return mouse button state:
		PsychGetMouseButtonState(buttonArray);
		// Query and return cursor position in global coordinates:
		GetCursorPos(&point);
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) point.x);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) point.y);
		
		// Window provided?
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetForegroundWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}		

		// Return optional valuator values: Unimplemented on Windows. Just return an empty matrix.
		// The &timestamp is just a dummy assignment without any meaning.
		PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, &timestamp);
		PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Microsoft Windows is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (firsttime) {
			// First time init:
			firsttime = 0;
			memset(keyState, 0, sizeof(keyState));
			memset(disabledKeys, 0, sizeof(disabledKeys));
			// These keycodes are always disabled: 0, 255:
			disabledKeys[0]=1;
			disabledKeys[255]=1;
			// Mouse buttone (left, right, middle) are also disabled by default:
			disabledKeys[1]=1;
			disabledKeys[2]=1;
			disabledKeys[4]=1;
	  }

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode
	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

			// Query state of all keys:
			for(i=1;i<255;i++){
				keyState[i] = (GetAsyncKeyState(i) & -32768) ? 1 : 0;
			}

	      // Disable all keys that are registered in disabledKeys. Check if
			// any non-disabled key is down.
	      for (i=0; i<256; i++) {
				if (disabledKeys[i]>0) keyState[i] = 0;
				keysdown+=(unsigned int) keyState[i];
	      }

	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a millisecond before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.001);

	    } while(1);

	    if (numButtons==-2) {
	      // KbWait mode: Copy out time value.
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);

	      // Copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      

	      // Copy out keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Build 256 elements return vector:
	      for(i=0; i<255; i++) {
		  		buttonStates[i] = (PsychNativeBooleanType)((keyState[i+1]) ? 1 : 0);
	      }
			// Special case: Null out last element:
			buttonStates[255] = (PsychNativeBooleanType) 0;
	    }
	  }
	  
	  if (numButtons==-3) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Determine our processID:
		currentProcess = GetCurrentProcess();
    
		// Get current scheduling policy:
		oldPriority = GetPriorityClass(currentProcess);
		
		// Map to PTB's scheme:
		switch(oldPriority) {
			case NORMAL_PRIORITY_CLASS:
				priorityLevel = 0;
			break;

			case HIGH_PRIORITY_CLASS:
				priorityLevel = 1;
			break;

			case REALTIME_PRIORITY_CLASS:
				priorityLevel = 2;
			break;

			default:
				priorityLevel = 0;
		}
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 2) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must not exceed 2.");

			switch(priorityLevel) {
				case 0: // Standard scheduling:
					SetPriorityClass(currentProcess, NORMAL_PRIORITY_CLASS);

					// Disable any MMCSS scheduling for us:
					PsychSetThreadPriority((psych_thread*) 0x1, 0, 0);
				break;
				
				case 1: // High priority scheduling:
					SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);

					// Additionally try to schedule us MMCSS: This will lift us roughly into the
					// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
					// on Vista and Windows-7 and later, however with a scheduler safety net applied.
					PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
				break;
				
				case 2: // Realtime scheduling:
					// This can fail if Matlab is not running under a user account with proper permissions:
					if ((0 == SetPriorityClass(currentProcess, REALTIME_PRIORITY_CLASS)) || (REALTIME_PRIORITY_CLASS != GetPriorityClass(currentProcess))) {
						// Failed to get RT-Scheduling. Let's try at least high priority scheduling:
						SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);
						
						// Additionally try to schedule us MMCSS: This will lift us roughly into the
						// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
						// on Vista and Windows-7 and later, however with a scheduler safety net applied.
						PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
					}
				break;
			}
		}
		// End of Priority() helper for Win32.
	  }
	}
#endif
	
#if PSYCH_SYSTEM == PSYCH_LINUX
	double myvaluators[100];
	int    numvaluators;
	unsigned char keys_return[32];
	char* keystring;
	PsychGenericScriptType *kbNames;
	CGDirectDisplayID dpy;
	Window rootwin, childwin, mywin;
	int i, j, mx, my, dx, dy;
	double mxd, myd, dxd, dyd;
	unsigned int mask_return;
	double timestamp;
	int numButtons;
	double* buttonArray;
	PsychNativeBooleanType* buttonStates;
	int keysdown;
	XEvent event_return;
	XKeyPressedEvent keypressevent;
	int screenNumber;
	int priorityLevel;
	struct sched_param schedulingparam;
	PsychWindowRecordType *windowRecord;
	int mouseIndex;
	XIButtonState buttons_return;
	XIModifierState modifiers_return;
	XIGroupState group_return;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);

	// Retrieve optional screenNumber argument:
	if (numButtons!=-5) {
		screenNumber = 0;
		if (PsychIsScreenNumberArg(2)) {
			PsychCopyInScreenNumberArg(2, FALSE, &screenNumber);
		}

		// Map screenNumber to X11 display handle and screenid:
		PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		if (PsychIsWindowIndexArg(2)) {
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			screenNumber = windowRecord->screenNumber;
			mywin = windowRecord->targetSpecific.xwindowHandle;

			// Map screenNumber to X11 display handle and screenid:
			PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		} else {
			mywin = RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber));
		}
	}

	// Default to "old school" mouse query - System default mouse via X core protocol:
	mouseIndex = -1;
	PsychCopyInIntegerArg(3, FALSE, &mouseIndex);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
	  // Mouse pointer query mode:
	  numvaluators = 0;

	  if (mouseIndex >= 0) {
		// XInput-2 query for handling of multiple mouse pointers:

		// Query input device list for screen:
		int nDevices;
		XIDeviceInfo* indevs = PsychGetInputDevicesForScreen(screenNumber, &nDevices);

		// Sanity check:
		if (NULL == indevs) PsychErrorExitMsg(PsychError_user, "Sorry, your system does not support individual mouse pointer queries.");
		if (mouseIndex >= nDevices) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such device.");
		if ((indevs[mouseIndex].use != XIMasterPointer) && (indevs[mouseIndex].use != XISlavePointer) && (indevs[mouseIndex].use != XIFloatingSlave)) {
			PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. Not a pointer device.");
		}

		// We requery the device info struct to retrieve updated live device state:
		// Crucial for slave pointers to get any state at all, but also needed on
		// master pointers to get the state of additional valuators, e.g., pen pressure,
		// touch area, tilt etc. for digitizer tablets, touch pads etc. For master pointers,
		// the primary 2 axis for 2D (x,y) position and the button/modifier state will be
		// queried via a dedicated XIQueryPointer() call, so that info gets overriden.
		indevs = XIQueryDevice(dpy, indevs[mouseIndex].deviceid, &numButtons);
		modifiers_return.effective = 0;

		// Query real number of mouse buttons and the raw button and axis state
		// stored inside the device itself. This is done mostly because slave pointer
		// devices don't support XIQueryPointer() so we get their relevant info from the
		// XIDeviceInfo struct itself:
		numButtons = 0;
		numvaluators = 0;
		memset(myvaluators, 0, sizeof(myvaluators));

		if (PsychIsArgPresent(PsychArgOut, 6)) {
			// Usercode wants valuator info structs:
			for (i = 0; i < indevs->num_classes; i++) if (indevs->classes[i]->type == XIValuatorClass) numIValuators++;
			PsychAllocOutStructArray(6, TRUE, numIValuators, numValuatorStructFieldNames, valuatorInfo, &valuatorStruct);
		}

		for (i = 0; i < indevs->num_classes; i++) {
			// printf("Class %i: Type %i\n", i, (int) indevs->classes[i]->type);
			if (indevs->classes[i]->type == XIButtonClass) {
				// Number of buttons: For all pointers.
				numButtons = ((XIButtonClassInfo*) indevs->classes[i])->num_buttons;

				// Button state for slave pointers. Will get overriden for master pointers:
				buttons_return.mask = ((XIButtonClassInfo*) indevs->classes[i])->state.mask;
				buttons_return.mask_len = ((XIButtonClassInfo*) indevs->classes[i])->state.mask_len;
			}

			// Axis state for slave pointers. First two axis (x,y) will get overriden for master pointers:
			if (indevs->classes[i]->type == XIValuatorClass) {
				XIValuatorClassInfo* axis = (XIValuatorClassInfo*) indevs->classes[i];
				if (axis->number == 0) mxd = axis->value;  // x-Axis.
				if (axis->number == 1) myd = axis->value;  // y-Axis.

				// Additional axis, e.g., digitizer tablet, touchpads etc.:
				if (axis->number >= 0 && axis->number < 100) {
					myvaluators[axis->number] = axis->value;
					numvaluators = (numvaluators >= axis->number + 1) ? numvaluators : axis->number + 1;
				}

				// Assign valuator info struct, if requested:
				if (valuatorStruct) {
					if (axis->label != None) {
						char* atomlabel =  XGetAtomName(dpy, axis->label);
						PsychSetStructArrayStringElement("label", axis->number, atomlabel, valuatorStruct);
						XFree(atomlabel);
					} else {
						PsychSetStructArrayStringElement("label", axis->number, "None", valuatorStruct);
					}

					PsychSetStructArrayDoubleElement("min", axis->number, (double) axis->min, valuatorStruct);
					PsychSetStructArrayDoubleElement("max", axis->number, (double) axis->max, valuatorStruct);
					PsychSetStructArrayDoubleElement("resolution", axis->number, (double) axis->resolution, valuatorStruct);
					PsychSetStructArrayDoubleElement("mode", axis->number, (double) axis->mode, valuatorStruct);
					PsychSetStructArrayDoubleElement("sourceID", axis->number, (double) axis->sourceid, valuatorStruct);
				}
				// printf("AXIS %i, LABEL = %s, MIN = %f, MAX = %f, VAL = %f\n", axis->number, (char*) "NONE", (float) axis->min, (float) axis->max, (float) axis->value);
			}
		}

		// Add 32 buttons for modifier key state vector:
		numButtons += 32;

		// A real master pointer: Use official query for mouse devices.
		if (indevs->use == XIMasterPointer) {
			// Query pointer location and state:
			XIQueryPointer(dpy, indevs->deviceid, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mxd, &myd, &dxd, &dyd,
				       &buttons_return, &modifiers_return, &group_return);
		}

		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, mxd);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, myd);

		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int) numButtons, (int)1, &buttonArray);
		memset(buttonArray, 0, sizeof(double) * numButtons);

		if (numButtons > 0) {
			// Mouse buttons:
			const int buttonOffset = 1; // Buttons start at bit 1, not 0 for some strange reason? At least so on Ubuntu 10.10 and 11.10 with 2 mice and 1 joystick?
			for (i = buttonOffset; (i < numButtons - 32) && ((i / 8 ) < buttons_return.mask_len); i++) {
				buttonArray[i - buttonOffset] = (double) ((buttons_return.mask[i / 8] & (1 << (i % 8))) ? 1 : 0);
			}

			// Free mask if retrieved via XIQueryPointer():
			if (indevs->use == XIMasterPointer) free(buttons_return.mask);

			// Append modifier key state from associated master keyboard. Last 32 entries:
			for (i = 0; i < 32; i++) {
				buttonArray[numButtons - 32 + i] = (double) ((modifiers_return.effective & (1 << i)) ? 1 : 0);
			}
		}

		// Release live state info structure:
		XIFreeDeviceInfo(indevs);
	  }
	  else {
		// Old school core protocol query of virtual core pointer:
		XQueryPointer(dpy, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mx, &my, &dx, &dy, &mask_return);
	  
		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) mx);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) my);
	  
		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);

		// Bits 8, 9 and 10 of mask_return seem to correspond to mouse buttons
		// 1, 2 and 3 of a mouse for some weird reason. Bits 0-7 describe keyboard modifier keys
		// like Alt, Ctrl, Shift, ScrollLock, NumLock, CapsLock...
		// We remap here, so the first three returned entries correspond to the mouse buttons and
		// the rest is attached behind, if requested...
	  
		// Mouse buttons: Left, Middle, Right == 0, 1, 2, aka 1,2,3 in Matlab space...
		for (i=0; i<numButtons && i<3; i++) {
			buttonArray[i] = (mask_return & (1<<(i+8))) ? 1 : 0; 
		}
		// Modifier keys 0 to 7 appended:
		for (i=3; i<numButtons && i<3+8; i++) {
			buttonArray[i] = (mask_return & (1<<(i-3))) ? 1 : 0; 
		}
		// Everything else appended:
		for (i=11; i<numButtons; i++) {
			buttonArray[i] = (mask_return & (1<<i)) ? 1 : 0; 
		}
	  }

	  // Return optional 4th argument: Focus state. Returns 1 if our window has
	  // keyboard input focus, zero otherwise:
	  XGetInputFocus(dpy, &rootwin, &i);
	  PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (rootwin == mywin) ? 1 : 0);

	  // Return optional valuator values:
	  PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) numvaluators, (int) 1, &myvaluators[0]);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Linux is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode:

	    // Switch X-Server into synchronous mode: We need this to get
	    // a higher timing precision.
	    XSynchronize(dpy, TRUE);

	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current keyboard state from X-Server:
	      XQueryKeymap(dpy, keys_return);

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

	      // Any key down?
	      for (i=0; i<32; i++) keysdown+=(unsigned int) keys_return[i];
	      
	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a few milliseconds before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.01);
	    } while(1);

	    if (numButtons==-2) {
	      // Copy out time:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);
	      // copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      
	      // Copy keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Map 32 times 8 bitvector to 256 element return vector:
	      for(i=0; i<32; i++) {
				for(j=0; j<8; j++) {
		  			buttonStates[i*8 + j] = (PsychNativeBooleanType)(keys_return[i] & (1<<j)) ? 1 : 0;
				}
	      }
	    }
	  }
	  else if (numButtons == -3) {
	    // numButtons == -3 --> KbName mapping mode:
	    // Return the full keyboard keycode to ASCII character code mapping table...
	    PsychAllocOutCellVector(1, kPsychArgOptional, 256, &kbNames);

	    for(i=0; i<256; i++) {
	      // Map keyboard scan code to KeySym:
	      keystring = XKeysymToString(XKeycodeToKeysym(dpy, i, 0));
	      if (keystring) {
		// Character found: Return its ASCII name string:
		PsychSetCellVectorStringElement(i, keystring, kbNames);
	      }
	      else {
		// No character for this keycode:
		PsychSetCellVectorStringElement(i, "", kbNames);
	      }
	    }
	  }
	  else if (numButtons == -4) {
	    // GetChar() emulation.

/* 	    do { */
/* 	      // Fetch next keypress event from queue, block if none is available... */
/* 	      keystring = NULL; */
/* 	      XNextEvent(dpy, &event_return); */
/* 	      // Check for valid keypress event and extract character: */
/* 	      if (event_return.type == KeyPress) { */
/* 		keypressevent = (XKeyPressedEvent) event_return; */
/* 		keystring = NULL; */
/* 		keystring = XKeysymToString(XKeycodeToKeysym(dpy, keypressevent.keycode, 0)); */
/* 	      } */
/* 	      // Repeat until a valid char is returned. */
/* 	    } while (keystring == NULL); */

/* 	    // Copy out character: */
/* 	    PsychCopyOutCharArg(1, kPsychArgOptional, (char) keystring); */
/* 	    // Copy out time: */
/* 	    PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) keypressevent.time); */
	  }
	  else if (numButtons==-5) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Query scheduling policy and priority:
		pthread_getschedparam(pthread_self(), &priorityLevel, &schedulingparam);

		// If scheduling mode is a realtime mode (RoundRobin realtime RR, or FIFO realtime),
		// then assign RT priority level (range 1-99) as current priorityLevel, otherwise
		// assign non realtime priority level zero:
		priorityLevel = (priorityLevel == SCHED_RR || priorityLevel == SCHED_FIFO) ? schedulingparam.sched_priority : 0;
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		errno=0;
		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 99 || priorityLevel < 0) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must be between zero and 99!");

			if (priorityLevel > 0) {
				// Realtime FIFO scheduling and all pages of Matlab/Octave locked into memory:
				schedulingparam.sched_priority = priorityLevel;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to enable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}
				else {
					// RT-Scheduling active. Lock all current and future memory:
					priorityLevel = mlockall(MCL_CURRENT | MCL_FUTURE);
					if (priorityLevel!=0) {
						// Failed! Report problem as warning, but don't worry further. 
	    					if(!PsychPrefStateGet_SuppressAllWarnings()) printf("PTB-WARNING: Failed to enable system memory locking with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						// Undo any possibly partial mlocks....
						munlockall();
						errno=0;
					}
				}
			}
			else {
				// Standard scheduling and no memory locking:
				schedulingparam.sched_priority = 0;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_OTHER, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to disable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}

				munlockall();
				errno=0;
			}
			// End of setup of new Priority...
		}
		// End of Priority() helper for Linux.
	  }
	}	// End of special functions handling for Linux...
#endif
	return(PsychError_none);	
}
PsychError SCREENGetCapturedImage(void) 
{
    PsychWindowRecordType		*windowRecord;
    PsychWindowRecordType		*textureRecord;
    PsychRectType				rect;
    double                      summed_intensity;
    int                         capturehandle = -1;
    int                         waitForImage = TRUE;
    int                         specialmode = 0;
	double						timeout, tnow;
    double                      presentation_timestamp = 0;
    int							rc=-1;
    double						targetmemptr = 0;
	double*						tsummed = NULL;
	psych_uint8					*targetmatrixptr = NULL;
	static rawcapimgdata		rawCaptureBuffer = {0, 0, 0, NULL};

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(6));            // Max. 6 input args.
    PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(4));           // Max. 4 output args.
    
    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    // Only onscreen windows allowed:
    if(!PsychIsOnscreenWindow(windowRecord) && !PsychIsOffscreenWindow(windowRecord)) {
        PsychErrorExitMsg(PsychError_user, "GetCapturedImage called on something else than an onscreen window or offscreen window.");
    }
    
    // Get the handle:
    PsychCopyInIntegerArg(2, TRUE, &capturehandle);
    if (capturehandle==-1) {
        PsychErrorExitMsg(PsychError_user, "GetCapturedImage called without valid handle to a capture object.");
    }

    // Get the 'waitForImage' flag: If waitForImage == true == 1, we'll do a blocking wait for
    // arrival of a new image. Otherwise we will return with a 0-Handle if there
    // isn't any new image available.
    PsychCopyInIntegerArg(3, FALSE, &waitForImage);

	// Special case waitForImage == 4? This would ask to call into the capture driver, but
	// not wait for any image to arrive and not return any information. This is only useful
	// on OS/X and Windows when using the capture engine for video recording to harddisk. In
	// that case we are not interested at all in the captured live video, we just want it to
	// get written to harddisk in the background. To keep the video encoder going, we need to
	// call its SGIdle() routine and waitForImage==4 does just that, call SGIdle().
	if (waitForImage == 4) {
		// Perform the null-call to the capture engine, ie a SGIdle() on OS/X and Windows:
		PsychGetTextureFromCapture(windowRecord, capturehandle, 4, 0.0, NULL, NULL, NULL, NULL);
		// Done. Nothing to return...
		return(PsychError_none);
	}
	
    // Get the optional textureRecord for the optional texture handle. If the calling script
    // provides the texture handle of an existing Psychtoolbox texture that has a matching
    // format, then that texture is recycled by overwriting its previous content with the
    // image data from the new captured image. This can save some overhead for texture destruction
    // and recreation. While this is probably not noticeable on mid- to high-end gfx cards with
    // rectangle texture support, it can provide a significant speedup on low-end gfx cards with
    // only power-of-two texture support.
    textureRecord = NULL;
    if ((PsychGetNumInputArgs()>=4) && PsychIsWindowIndexArg(4)) PsychAllocInWindowRecordArg(4, FALSE, &textureRecord);
    
    // Get the optional specialmode flag:
    PsychCopyInIntegerArg(5, FALSE, &specialmode);

	// Set a 10 second maximum timeout for waiting for new frames:
	PsychGetAdjustedPrecisionTimerSeconds(&timeout);
	timeout+=10;

    while (rc==-1) {		
      // We pass a checkForImage value of 2 if waitForImage>0. This way we can signal if we are in polling or blocking mode.
      // With the libdc1394 engine this allows to do a real blocking wait in the driver -- much more efficient than the spin-waiting approach!
      rc = PsychGetTextureFromCapture(windowRecord, capturehandle, ((waitForImage>0 && waitForImage<3) ? 2 : 1), 0.0, NULL, &presentation_timestamp, NULL, &rawCaptureBuffer);
		PsychGetAdjustedPrecisionTimerSeconds(&tnow);
        if (rc==-2 || (tnow > timeout)) {
            // No image available and there won't be any in the future, because capture has been stopped or there is a timeout:
			if (tnow > timeout) printf("PTB-WARNING: In Screen('GetCapturedImage') timed out waiting for a new frame. No video data in over 10 seconds!\n");

            // No new texture available: Return a negative handle:
            PsychCopyOutDoubleArg(1, TRUE, -1);
            // ...and an invalid timestamp:
            PsychCopyOutDoubleArg(2, FALSE, -1);
            PsychCopyOutDoubleArg(3, FALSE, 0);
            PsychCopyOutDoubleArg(4, FALSE, 0);

            // Ready!
            return(PsychError_none);
        }
        else if (rc==-1 && (waitForImage == 0 || waitForImage == 3)) {
            // We should just poll once and no new texture available: Return a null-handle:
            PsychCopyOutDoubleArg(1, TRUE, 0);
            // ...and the current timestamp:
            PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);
            PsychCopyOutDoubleArg(3, FALSE, 0);
            PsychCopyOutDoubleArg(4, FALSE, 0);

            // Ready!
            return(PsychError_none);
        }
        else if (rc==-1 && waitForImage != 0) {
            // No new texture available yet. Just sleep a bit and then retry...
            PsychYieldIntervalSeconds(0.002);
        }
    }

    // rc == 0 --> New image available: Go ahead...
    if (waitForImage!=2 && waitForImage!=3) {
      // Ok, we need a texture for the image. Did script provide an old one for recycling?
      if (textureRecord) {
	// Old texture provided for reuse? Some basic sanity check: Everything else is
	// up to the lower level PsychGetTextureFromCapture() routine.
        if(!PsychIsOffscreenWindow(textureRecord)) {
	  PsychErrorExitMsg(PsychError_user, "GetCapturedImage provided with something else than a texture as fourth call parameter.");
        }	
      }
      else {
        // No old texture provided: Create a new texture record:
        PsychCreateWindowRecord(&textureRecord);

        // Set mode to 'Texture':
        textureRecord->windowType=kPsychTexture;

        // We need to assign the screen number of the onscreen-window.
        textureRecord->screenNumber=windowRecord->screenNumber;

        // It defaults to a 32 bit texture for captured images. On Linux, this will be overriden,
		// if optimized formats exist for our purpose:
        textureRecord->depth=32;
		textureRecord->nrchannels = 4;

        // Create default rectangle which describes the dimensions of the image. Will be overwritten
        // later on.
        PsychMakeRect(rect, 0, 0, 10, 10);
        PsychCopyRect(textureRecord->rect, rect);
        
        // Other setup stuff:
        textureRecord->textureMemorySizeBytes= 0;
        textureRecord->textureMemory=NULL;
        
        // Assign parent window and copy its inheritable properties:
		PsychAssignParentWindow(textureRecord, windowRecord);

        // Set textureNumber to zero, which means "Not cached, do not recycle"
        // Todo: Texture recycling like in PsychMovieSupport for higher efficiency!
        textureRecord->textureNumber = 0;
      }

      // Power-of-two texture requested?
      if (specialmode & 0x01) {
		// Yes. Spec it:
		textureRecord->texturetarget = GL_TEXTURE_2D;
      }
    }
    else {
        // Just want to return summed_intensity and timestamp, not real texture...
        textureRecord = NULL;
    }

	// Default to no calculation of summed image intensity:
	tsummed = NULL;
    if ((PsychGetNumOutputArgs() > 3) && !(specialmode & 0x2)) {
        // Return sum of pixel intensities for all channels of this image: Need to
		// assign the output pointer for this to happen:
		tsummed = &summed_intensity;
	}

    // Try to fetch an image from the capture object and return it as texture:
	targetmatrixptr = NULL;
	
	// Shall we return a Matlab matrix?
	if ((PsychGetNumOutputArgs() > 3) && (specialmode & 0x2)) {
		// We shall return a matrix with raw image data. Allocate a uint8 matrix
		// of sufficient size:
		PsychAllocOutUnsignedByteMatArg(4, TRUE, rawCaptureBuffer.depth, rawCaptureBuffer.w, rawCaptureBuffer.h, &targetmatrixptr);
		tsummed = NULL;
	}
	
	// Shall we return data into preallocated memory buffer?
	if (specialmode & 0x4) {
		// Copy in memory address (which itself is encoded in a double value):
		PsychCopyInDoubleArg(6, TRUE, &targetmemptr);
		targetmatrixptr = (psych_uint8*) PsychDoubleToPtr(targetmemptr);
	}
	
	if (targetmatrixptr == NULL) {
		// Standard fetch of a texture and its timestamp:
		rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, NULL);
	}
	else {
		// Fetch of a memory raw image buffer + timestamp + possibly a texture:
		rawCaptureBuffer.data = (void*) targetmatrixptr;
		rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, &rawCaptureBuffer);			
	}
	
    if (tsummed) {
        // Return sum of pixel intensities for all channels of this image:
        PsychCopyOutDoubleArg(4, FALSE, summed_intensity);
    }

    // Real texture requested?
    if (textureRecord) {
        // Texture ready for consumption.

		// Assign GLSL filter-/lookup-shaders if needed: usefloatformat is always == 0 as
		// our current capture engine implementations only return 8 bpc fixed textures.
		// The 'userRequest' flag is set if specialmode flag is set to 8.
		PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, 0, (specialmode & 8) ? 1 : 0);

        // specialmode setting 16? Disable auto-mipmap generation:
        if (specialmode & 16) textureRecord->specialflags |= kPsychDontAutoGenMipMaps;    

		// Mark it valid and return handle to userspace:
        PsychSetWindowRecordValid(textureRecord);
        PsychCopyOutDoubleArg(1, TRUE, textureRecord->windowIndex);
    }
    else {
        PsychCopyOutDoubleArg(1, TRUE, 0);
    }
    
    // Return presentation timestamp for this image:
    PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);

    // Return count of pending frames in buffers or of dropped frames:
    PsychCopyOutDoubleArg(3, FALSE, (double) rc);

    // Ready!
    return(PsychError_none);
}
PsychError SCREENOpenOffscreenWindow(void) 
{
    int						screenNumber, depth, targetScreenNumber;
    PsychRectType			rect;
    PsychColorType			color;
    PsychWindowRecordType	*exampleWindowRecord, *windowRecord, *targetWindow;
    psych_bool				wasColorSupplied;
    char*					texturePointer;
    size_t					xSize, ySize, nbytes;
    psych_bool				bigendian;
	GLubyte					*rpb;
    int						ix;
	GLenum					fboInternalFormat;
	psych_bool				needzbuffer;
	psych_bool				overridedepth = FALSE;
	int						usefloatformat = 0;
	int						specialFlags = 0;
	int						multiSample = 0;
	
    // Detect endianity (byte-order) of machine:
    ix=255;
    rpb=(GLubyte*) &ix;
    bigendian = ( *rpb == 255 ) ? FALSE : TRUE;
    ix = 0; rpb = NULL;

    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //cap the number of inputs
    PsychErrorExit(PsychCapNumInputArgs(6));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    //1-User supplies a window ptr 2-User supplies a screen number 3-User supplies rect and pixel size
    if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1, TRUE, &exampleWindowRecord);
		// Assign normalized copy of example windows rect -- Top-Left corner is always (0,0)
		PsychNormalizeRect(exampleWindowRecord->clientrect, rect);

        // We copy depth only from exampleWindow if it is a offscreen window (=texture). Copying from
        // onscreen windows doesn't make sense, e.g. depth=16 for onscreen means RGBA8 window, but it
        // would map onto a LUMINANCE+ALPHA texture for the offscreen window! We always use 32 bit RGBA8
        // in such a case.
        depth=(PsychIsOffscreenWindow(exampleWindowRecord)) ? exampleWindowRecord->depth : 32;
		// unless it is a FBO backed onscreen window in imaging mode: Then we can use the depth from it.
		if (exampleWindowRecord->imagingMode & kPsychNeedFastBackingStore || exampleWindowRecord->imagingMode & kPsychNeedFastOffscreenWindows) depth = exampleWindowRecord->depth;
        targetScreenNumber=exampleWindowRecord->screenNumber;
        targetWindow=exampleWindowRecord;
    } else if(PsychIsScreenNumberArg(1)){
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        PsychGetScreenRect(screenNumber, rect);
        depth=32; // Always use RGBA8 in this case! See above...
        targetScreenNumber=screenNumber;
        targetWindow=NULL;
    } else if(PsychIsUnaffiliatedScreenNumberArg(1)){  //that means -1 or maybe also NaN if we add that option.  
        // Default to a depth of 32 bpp:
        depth = 32;
        targetWindow = NULL;
        // Get first open onscreen window as target window:
        PsychFindScreenWindowFromScreenNumber(kPsychUnaffiliatedWindow, &targetWindow);
		if (targetWindow == NULL) PsychErrorExitMsg(PsychError_user, "Could not find any open onscreen window to act as parent for this offscreen window. Open an onscreen window first!");
		targetScreenNumber = targetWindow->screenNumber;
        PsychGetScreenRect(targetScreenNumber, rect);
    } else {
        targetScreenNumber = 0; // Make compiler happy.
        PsychErrorExit(PsychError_invalidNumdex);
    }

    if (targetWindow==NULL) {
        // Get target window of screen:
        PsychFindScreenWindowFromScreenNumber(targetScreenNumber, &targetWindow);
		if (targetWindow == NULL) PsychErrorExitMsg(PsychError_user, "Could not find any open onscreen window to act as parent for this offscreen window. Open an onscreen window first!");
		targetScreenNumber = targetWindow->screenNumber;
    }
    
    //Depth and rect argument supplied as arguments override those inherited from reference screen or window.
    //Note that PsychCopyIn* prefix means that value will not be overwritten if the arguments are not present.
    PsychCopyInRectArg(3,FALSE, rect);
    if (IsPsychRectEmpty(rect)) PsychErrorExitMsg(PsychError_user, "Invalid rect value provided: Empty rects are not allowed.");

	// Copy in optional depth: This gets overriden in many ways if imaging pipeline is on:
    if (PsychCopyInIntegerArg(4,FALSE, &depth)) overridedepth = TRUE;

    // If any of the no longer supported values 0, 1, 2 or 4 is provided, we
    // silently switch to 32 bits per pixel, which is the safest and fastest setting:
    if (depth==0 || depth==1 || depth==2 || depth==4) depth=32;

    // Final sanity check:
	if (!(targetWindow->imagingMode & kPsychNeedFastOffscreenWindows) && !(targetWindow->imagingMode & kPsychNeedFastBackingStore) && (depth==64 || depth==128)) {
      PsychErrorExitMsg(PsychError_user, "Invalid depth value provided. Must be 8 bpp, 16 bpp, 24 bpp or 32 bpp, unless you enable the imaging pipeline, which provides you with more options!");
	}
	
    if (depth!=8 && depth!=16 && depth!=24 && depth!=32 && depth!=64 && depth!=128) {
      PsychErrorExitMsg(PsychError_user, "Invalid depth value provided. Must be 8 bpp, 16 bpp, 24 bpp, 32 bpp, or if imagingmode is enabled also 64 bpp or 128 bpp!");
    }

	// If the imaging pipeline is enabled for the associated onscreen window and fast backing store, aka FBO's
	// is requested, then we only accept depths of at least 32 bit, i.e. RGBA windows. We override any lower
	// precision spec. This is because some common hardware only supports rendering to RGBA textures, not to
	// RGB, LA or Luminance textures.
	if ((targetWindow->imagingMode & kPsychNeedFastBackingStore || targetWindow->imagingMode & kPsychNeedFastOffscreenWindows) && (depth < 32)) depth = 32;

    // Find the color for the window background.  
    wasColorSupplied=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color);
	
	// If none provided, use a proper white-value for this window:
    if(!wasColorSupplied) PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromWindow(targetWindow));  

    // Get the optional specialmode flag:
    PsychCopyInIntegerArg(5, FALSE, &specialFlags);

    // OpenGL-ES only supports GL_TEXTURE_2D targets, so enforce these via flags setting 1:
    if (PsychIsGLES(targetWindow)) specialFlags |= 1;

	// This command converts whatever color we got into RGBA format:
    PsychCoerceColorMode(&color);

    // printf("R=%i G=%i B=%i A=%i I=%i", color.value.rgba.r, color.value.rgba.g,color.value.rgba.b,color.value.rgba.a,color.value.index); 
    // First allocate the offscreen window record to store stuff into. If we exit with an error PsychErrorExit() should
    // call PsychPurgeInvalidWindows which will clean up the window record. 
    PsychCreateWindowRecord(&windowRecord);  // This also fills the window index field.

    // This offscreen window is implemented as a Psychtoolbox texture:
    windowRecord->windowType=kPsychTexture;

    // We need to assign the screen number of the onscreen-window, so PsychCreateTexture()
    // can query the size of the screen/onscreen-window...
    windowRecord->screenNumber = targetScreenNumber;

    // Assign the computed depth:
    windowRecord->depth=depth;

	// Default number of channels:
	windowRecord->nrchannels=depth / 8;

    // Assign the computed rect, but normalize it to start with top-left at (0,0):
    PsychNormalizeRect(rect, windowRecord->rect);

    // Client rect of an offscreen window is always == rect of it:
    PsychCopyRect(windowRecord->clientrect, windowRecord->rect);
    
	// Until here no OpenGL commands executed. Now we need a valid context: Set targetWindow
	// as drawing target. This will perform neccessary context-switch and all backbuffer
	// backup/restore/whatever operations to make sure we can do what we want without
	// possibly screwing any offscreen windows and bindings:
	if (PsychIsOnscreenWindow(targetWindow) || PsychIsOffscreenWindow(targetWindow)) {
		// This is a possible on-/offscreen drawingtarget:
		PsychSetDrawingTarget(targetWindow);
	}
	else {
		// This must be a proxy-window object: Can't transition to it!
		
		// But we can safe-reset the current drawingtarget...
		PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
		
		// ...and then switch to the OpenGL context of the 'targetWindow' proxy object:
		PsychSetGLContext(targetWindow);

		// Ok, framebuffer and bindings are safe and disabled, context is set. We
		// should be safe to continue with the proxy...
	}
	
	// From here on we have a defined context and state. We can detach the drawing target whenever
	// we want, as everything is backed up somewhere for later reinit.
	
	// Create offscreen window either new style as FBO, or old style as texture:
	if ((targetWindow->imagingMode & kPsychNeedFastBackingStore) || (targetWindow->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Imaging mode for this window enabled: Use new way of creating the offscreen window:
		
		// We safely unbind any FBO bindings and drawingtargets:
		PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
		
		// Overriden for imagingmode: There we always have 4 channels...
		windowRecord->nrchannels=4;

		// Start off with standard 8 bpc fixed point:
		fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
		
		// Need 16 bpc fixed point precision?
		if (targetWindow->imagingMode & kPsychNeed16BPCFixed) {
			fboInternalFormat = (targetWindow->gfxcaps & kPsychGfxCapSNTex16) ? GL_RGBA16_SNORM : GL_RGBA16;
			windowRecord->depth=64;
			usefloatformat = 0;
		}
		
		// Need 16 bpc floating point precision?
		if (targetWindow->imagingMode & kPsychNeed16BPCFloat) { fboInternalFormat = GL_RGBA_FLOAT16_APPLE; windowRecord->depth=64; usefloatformat = 1; }
		
		// Need 32 bpc floating point precision?
		if (targetWindow->imagingMode & kPsychNeed32BPCFloat) { fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2; }
		
		// Override depth value provided?
		if (overridedepth) {
			// Manual depth specified: Override with that depth:
			switch(depth) {
				case 32:
					fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
				break;

				case 64:
					fboInternalFormat = GL_RGBA_FLOAT16_APPLE; windowRecord->depth=64; usefloatformat = 1;
					// Need fallback for lack of float 16 support?
					if (!(targetWindow->gfxcaps & kPsychGfxCapFPTex16) && !PsychIsGLES(targetWindow)) {
						// Yes. Try 16 bit signed normalized texture instead:
						if (PsychPrefStateGet_Verbosity() > 4)
							printf("PTB-INFO:OpenOffscreenWindow: Code requested 16 bpc float precision, but this is unsupported. Trying to use 15 bit snorm precision instead.\n");
						fboInternalFormat = GL_RGBA16_SNORM; windowRecord->depth=64; usefloatformat = 0;
						if (!(targetWindow->gfxcaps & kPsychGfxCapSNTex16)) {
							printf("PTB-ERROR:OpenOffscreenWindow: Code requested 16 bpc float precision, but this is unsupported by this graphics card.\n");
							printf("PTB-ERROR:OpenOffscreenWindow: Tried to use 16 bit snorm format instead, but failed as this is unsupported as well.\n");
						}
					}
				break;

				case 128:
					fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2;
				break;
				
				default:
					fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
			}			
		}
		
        // Floating point framebuffer on OpenGL-ES requested?
        if (PsychIsGLES(targetWindow) && (usefloatformat > 0)) {
            // Yes. We only support 32 bpc float framebuffers with alpha-blending. On less supportive hardware we fail:
            if (!(targetWindow->gfxcaps & kPsychGfxCapFPTex32) || !(targetWindow->gfxcaps & kPsychGfxCapFPFBO32)) {
                PsychErrorExitMsg(PsychError_user, "Sorry, the requested offscreen window color resolution of 32 bpc floating point is not supported by your graphics card. Game over.");
            }

            // Supported. Upgrade requested format to 32 bpc float, whatever it was before:
            fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2;
        }

		// Do we need additional depth buffer attachments?
		needzbuffer = (PsychPrefStateGet_3DGfx()>0) ? TRUE : FALSE;
		
		// Copy in optional multiSample argument: It defaults to zero, aka multisampling disabled.
		PsychCopyInIntegerArg(6, FALSE, &multiSample);
		if (multiSample < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative multiSample level provided!");

		// Multisampled anti-aliasing requested?
		if (multiSample > 0) {
			// Yep. Supported by GPU?
			if (!(targetWindow->gfxcaps & kPsychGfxCapFBOMultisample)) {
				// No. We fall back to non-multisampled mode:
				multiSample = 0;
				
				// Tell user if warnings enabled:
				if (PsychPrefStateGet_Verbosity() > 1) {
					printf("PTB-WARNING: You requested stimulus anti-aliasing via multisampling by setting the multiSample parameter of Screen('OpenOffscreenWindow', ...) to a non-zero value.\n");
					printf("PTB-WARNING: You also requested use of the imaging pipeline. Unfortunately, your combination of operating system, graphics hardware and driver does not\n");
					printf("PTB-WARNING: support simultaneous use of the imaging pipeline and multisampled anti-aliasing.\n");
					printf("PTB-WARNING: Will therefore continue without anti-aliasing...\n\n");
					printf("PTB-WARNING: A driver upgrade may resolve this issue. Users of MacOS-X need at least OS/X 10.5.2 Leopard for support on recent ATI hardware.\n\n");
				}
			}
		}

		// Allocate framebuffer object for this Offscreen window:
		if (!PsychCreateFBO(&(windowRecord->fboTable[0]), fboInternalFormat, needzbuffer, (int) PsychGetWidthFromRect(rect), (int) PsychGetHeightFromRect(rect), multiSample, specialFlags)) {
			// Failed!
			PsychErrorExitMsg(PsychError_user, "Creation of Offscreen window in imagingmode failed for some reason :(");
		}

		// Assign this FBO as drawBuffer for mono channel of our Offscreen window:
		windowRecord->drawBufferFBO[0] = 0;
		windowRecord->fboCount = 1;
		
		// Assign it as texture as well:
		windowRecord->textureNumber = windowRecord->fboTable[0]->coltexid;
		windowRecord->textureMemorySizeBytes = 0;
		windowRecord->textureMemory = NULL;
		windowRecord->texturetarget = (specialFlags & 0x1) ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_EXT;
		windowRecord->surfaceSizeBytes = (size_t) (PsychGetWidthFromRect(rect) * PsychGetHeightFromRect(rect) * (windowRecord->depth / 8));

		// Set bpc for FBO backed offscreen window:
		windowRecord->bpc = (int) (windowRecord->depth / 4);

		// Initial setup done, continues below after some shared code...
	}
	else {
		// Traditional texture creation code:
		
		// Special case for alpha-channel: DBL_MAX signals maximum alpha
		// value requested. In our own code we need to manually map this to
		// the maximum uint8 alpha value of 255:
		if (color.value.rgba.a == DBL_MAX) color.value.rgba.a = 255;
		
		// Allocate the texture memory:
		// We only allocate the amount really needed for given format, aka numMatrixPlanes - Bytes per pixel.
		xSize = (size_t) PsychGetWidthFromRect(rect);
		ySize = (size_t) PsychGetHeightFromRect(rect);
		windowRecord->textureMemorySizeBytes = ((size_t) (depth/8)) * xSize * ySize;
		windowRecord->textureMemory = malloc(windowRecord->textureMemorySizeBytes);
		texturePointer=(char*) windowRecord->textureMemory;
		// printf("depth=%i xsize=%i ysize=%i mem=%i ptr=%p", depth, xSize, ySize, windowRecord->textureMemorySizeBytes, texturePointer);
		// Fill with requested background color:
		nbytes=0;
		switch (depth) {
			case 8: // Pure LUMINANCE texture:
				memset((void*) texturePointer, (int) color.value.rgba.r, windowRecord->textureMemorySizeBytes);
				break;
				
			case 16: // LUMINANCE + ALPHA
				while (nbytes < windowRecord->textureMemorySizeBytes) {
					*(texturePointer++) = (psych_uint8) color.value.rgba.r;
					*(texturePointer++) = (psych_uint8) color.value.rgba.a;
					nbytes+=2;
				}
				break;
				
			case 24: // RGB:
				while (nbytes < windowRecord->textureMemorySizeBytes) {
					*(texturePointer++) = (psych_uint8) color.value.rgba.r;
					*(texturePointer++) = (psych_uint8) color.value.rgba.g;
					*(texturePointer++) = (psych_uint8) color.value.rgba.b;
					nbytes+=3;
				}
				break;        
				
			case 32: // RGBA
				if (bigendian) {
					// Code for big-endian machines, e.g., PowerPC:
					while (nbytes < windowRecord->textureMemorySizeBytes) {
						*(texturePointer++) = (psych_uint8) color.value.rgba.a;
						*(texturePointer++) = (psych_uint8) color.value.rgba.r;
						*(texturePointer++) = (psych_uint8) color.value.rgba.g;
						*(texturePointer++) = (psych_uint8) color.value.rgba.b;
						nbytes+=4;
					}
				}
				else {
					// Code for little-endian machines, e.g., IntelPC, IntelMAC, aka Pentium.
					while (nbytes < windowRecord->textureMemorySizeBytes) {
						*(texturePointer++) = (psych_uint8) color.value.rgba.b;
						*(texturePointer++) = (psych_uint8) color.value.rgba.g;
						*(texturePointer++) = (psych_uint8) color.value.rgba.r;
						*(texturePointer++) = (psych_uint8) color.value.rgba.a;
						nbytes+=4;
					}
				}
				break;
		}
	}
	
	// Shared setup code for FBO vs. non-FBO Offscreen windows:
	
	// Assign parent window and copy its inheritable properties:
	PsychAssignParentWindow(windowRecord, targetWindow);
	
    // Texture orientation is type 2 aka upright, non-transposed aka Offscreen window:
    windowRecord->textureOrientation = 2;
    
	if ((windowRecord->imagingMode & kPsychNeedFastBackingStore) || (windowRecord->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Last step for FBO backed Offscreen window: Clear it to its background color:
		PsychSetDrawingTarget(windowRecord);

		// Set default draw shader:
		PsychSetShader(windowRecord, -1);
	
		// Set background fill color:
		PsychSetGLColor(&color, windowRecord);

		// Setup alpha-blending:
		PsychUpdateAlphaBlendingFactorLazily(windowRecord);

		// Fullscreen fill of a non-onscreen window:
		PsychGLRect(windowRecord->rect);

		// Multisampling requested? If so, we need to enable it:
		if (multiSample > 0) {
			glEnable(GL_MULTISAMPLE);
			while (glGetError() != GL_NO_ERROR);
		}
		
		// Ready. Unbind it.
		PsychSetDrawingTarget(NULL);		
	}
	else {
		// Old-style setup for non-FBO Offscreen windows:
        
        // Special texture format?
		if (specialFlags & 0x1) windowRecord->texturetarget = GL_TEXTURE_2D;
        
		// Let's create and bind a new texture object and fill it with our new texture data.
		PsychCreateTexture(windowRecord);
    }

	// Assign GLSL filter-/lookup-shaders if needed:
	PsychAssignHighPrecisionTextureShaders(windowRecord, targetWindow, usefloatformat, (specialFlags & 2) ? 1 : 0);
	
    // specialFlags setting 8? Disable auto-mipmap generation:
    if (specialFlags & 0x8) windowRecord->specialflags |= kPsychDontAutoGenMipMaps;    

    // A specialFlags setting of 32? Protect texture against deletion via Screen('Close') without providing a explicit handle:
    if (specialFlags & 32) windowRecord->specialflags |= kPsychDontDeleteOnClose;    

    // Window ready. Mark it valid and return handle to userspace:
    PsychSetWindowRecordValid(windowRecord);
    
    //Return the window index and the rect argument.
    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);
    PsychCopyOutRectArg(2, FALSE, rect);

    // Ready.
    return(PsychError_none);
}