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);	
}
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);
}
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);
}
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);
}
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 SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	Boolean					preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt;
	double					returnDoubleValue, inputDoubleValue;
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(3));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(1));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;
			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs==2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_3DGfx(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	return(PsychError_none);
}
PsychError SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	psych_bool				preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt, tempInt2, tempInt3, tempInt4;
	double					returnDoubleValue, inputDoubleValue;
	double					maxStddev, maxDeviation, maxDuration;
	int						minSamples;
    double                  *dheads = NULL;

	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(5));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(4));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) (psych_int64) getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;			
		}else 
		if(PsychMatch(preferenceName, "TextEncodingLocale")){
			PsychCopyOutCharArg(1, kPsychArgOptional, PsychGetUnicodeTextConversionLocale());
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				if (!PsychSetUnicodeTextConversionLocale(newFontName)) PsychErrorExitMsg(PsychError_user, "Setting the 'TextEncodingLocale' failed, most likely because you provided an invalid/unknown locale setting string.");
			}
			preferenceNameArgumentValid=TRUE;			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "OverrideMultimediaEngine")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_UseGStreamer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_UseGStreamer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextAntiAliasing")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextAntiAliasing());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextAntiAliasing(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextRenderer")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextRenderer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextRenderer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SyncTestSettings")){
			PsychPrefStateGet_SynctestThresholds(&maxStddev, &minSamples, &maxDeviation, &maxDuration);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, maxStddev);
			PsychCopyOutDoubleArg(2, kPsychArgOptional, minSamples);
			PsychCopyOutDoubleArg(3, kPsychArgOptional, maxDeviation);
			PsychCopyOutDoubleArg(4, kPsychArgOptional, maxDuration);
			if(numInputArgs>=2){
							PsychCopyInDoubleArg( 2, kPsychArgOptional, &maxStddev);
                            PsychCopyInIntegerArg(3, kPsychArgOptional, &minSamples);
							PsychCopyInDoubleArg( 4, kPsychArgOptional, &maxDeviation);
							PsychCopyInDoubleArg( 5, kPsychArgOptional, &maxDuration);
							PsychPrefStateSet_SynctestThresholds(maxStddev, minSamples, maxDeviation, maxDuration);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLEndlineOverride")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLEndlineOverride());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLEndlineOverride(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "DefaultVideocaptureEngine")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VideoCaptureEngine());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_VideoCaptureEngine(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "WindowShieldingLevel")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_WindowShieldingLevel());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_WindowShieldingLevel(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM") || PsychMatch(preferenceName, "Workarounds1")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "FrameRectCorrection")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_FrameRectCorrection());
					if(numInputArgs==2){
						PsychCopyInDoubleArg(2, kPsychArgRequired, &inputDoubleValue);
						PsychPrefStateSet_FrameRectCorrection(inputDoubleValue);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_3DGfx(tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SynchronizeDisplays")){
				if(numInputArgs >= 2) {
					// This is a special call: It currently doesn't set a preference setting,
					// but instead triggers an instantaneous synchronization of all available
					// display heads, if possible. We may have a more clever and "standard" interface
					// interface for this later on, but for first tests this will do.
					// Syncmethod is hard-coded to 0 -> Use whatever's available to sync.
					// timeout for retries is 5.0 seconds.
					// Acceptable residual offset is +/- 2 scanlines.
					// Returns the real residual offset after sync.
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					if (!PsychCopyInIntegerArg(3, kPsychArgOptional, &tempInt3)) {
                        // No screenId specified: Resync default screen or whatever...
                        tempInt2 = 0;
                        if (PsychSynchronizeDisplayScreens(&tempInt2, NULL, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
                    } else {
                        // Specific screenId provided: Resync crtc's associated with this screenId if possible:
                        tempInt2 = 1;
                        if (PsychSynchronizeDisplayScreens(&tempInt2, &tempInt3, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
                    }
                    
					PsychCopyOutDoubleArg(1, kPsychArgOptional, tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ScreenToHead")){
				// screenId is required:
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				if (tempInt < 0 || tempInt >= PsychGetNumDisplays() || tempInt >= kPsychMaxPossibleDisplays) PsychErrorExitMsg(PsychError_user, "Invalid screenId provided. Out of valid range!");

				// Return old mappings for this screenId:
                for (tempInt2 = 0; (tempInt2 < kPsychMaxPossibleCrtcs) && (PsychPrefStateGet_ScreenToHead(tempInt, tempInt2) >= 0); tempInt2++);
                PsychAllocOutDoubleMatArg(1, kPsychArgOptional, 2, tempInt2, 1, &dheads);
                
                tempInt4 = 0;
                for (tempInt3 = 0; tempInt3 < tempInt2; tempInt3++) {
                    dheads[tempInt4++] = (double) PsychPrefStateGet_ScreenToHead(tempInt, tempInt3);
                    dheads[tempInt4++] = (double) PsychPrefStateGet_ScreenToCrtcId(tempInt, tempInt3);
                }
                
                // Optionally retrieve and set new mappings for this screenId:
				if(numInputArgs>=3) {
					// Set new headId for screenId:
					PsychCopyInIntegerArg(3, kPsychArgRequired, &tempInt2);
					if (tempInt2 < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative headId provided!");

					// Set new crtcId for screenId:
					PsychCopyInIntegerArg(4, kPsychArgRequired, &tempInt3);
					if (tempInt3 < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative crtcId provided!");

                    // Assign primary head by default (index 0), but allow optionally others as well:
                    tempInt4 = 0;
					PsychCopyInIntegerArg(5, kPsychArgOptional, &tempInt4);
					if (tempInt4 < 0 || tempInt4 >= kPsychMaxPossibleCrtcs) PsychErrorExitMsg(PsychError_user, "Invalid rankId provided! Too many heads for one screen!");

					PsychPrefStateSet_ScreenToHead(tempInt, tempInt2, tempInt3, tempInt4);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	return(PsychError_none);
}
PsychError SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	Boolean					preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt, tempInt2, tempInt3;
	double					returnDoubleValue, inputDoubleValue;
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(3));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(1));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;
			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextAntiAliasing")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextAntiAliasing());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextAntiAliasing(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextRenderer")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextRenderer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextRenderer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLEndlineOverride")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLEndlineOverride());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLEndlineOverride(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "DefaultVideocaptureEngine")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VideoCaptureEngine());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_VideoCaptureEngine(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM") || PsychMatch(preferenceName, "Workarounds1")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_3DGfx(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SynchronizeDisplays")){
				if(numInputArgs==2){
					// This is a special call: It currently doesn't set a preference setting,
					// but instead triggers an instantaneous synchronization of all available
					// display heads, if possible. We may have a more clever and "standard" interface
					// interface for this later on, but for first tests this will do.
					// Syncmethod is hard-coded to 0 -> Use whatever's available to sync.
					// timeout for retries is 5.0 seconds.
					// Acceptable residual offset is +/- 2 scanlines.
					// Returns the real residual offset after sync.
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					tempInt2 = 0;
					if (PsychSynchronizeDisplayScreens(&tempInt2, NULL, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
					PsychCopyOutDoubleArg(1, kPsychArgOptional, tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	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);
}