Exemple #1
0
void
COSXScreen::hideCursor()
{
	LOG((CLOG_DEBUG "hiding cursor"));

	CFStringRef propertyString = CFStringCreateWithCString(
		NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman);

	CGSSetConnectionProperty(
		_CGSDefaultConnection(), _CGSDefaultConnection(),
		propertyString, kCFBooleanTrue);

	CFRelease(propertyString);

	CGError error = CGDisplayHideCursor(m_displayID);
	if (error != kCGErrorSuccess) {
		LOG((CLOG_ERR "failed to hide cursor, error=%d", error));
	}

	// appears to fix "mouse randomly not hiding" bug
	CGAssociateMouseAndMouseCursorPosition(true);

	if (CGCursorIsVisible()) {
		LOG((CLOG_WARN "cursor may be still visible"));
	}

	m_cursorHidden = true;
}
Exemple #2
0
void
COSXScreen::hideCursor()
{
    CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman);
    CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue);
    CFRelease(propertyString);

    CGDisplayHideCursor(m_displayID);
    LOG((CLOG_DEBUG "Trying to hide cursor."));
}
void orderAboveWindow(int wid, int above) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
    CGSOrderWindow(cid, wid, kCGSOrderAbove, above);
	CGSFlushWindow(cid, wid, 0);
}
Exemple #4
0
void DEHandleOrderEvent(DecEvent* event)
{	
	DecEventOrder* eventOrder = dec_event_order_new(event); 
	if (eventOrder == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_order_free(eventOrder); 
		return; 
	}
	
	CGSConnection iConnection; 
	
	int place		= dec_event_order_place_get(eventOrder); 
	int reference	= dec_event_order_reference_get(eventOrder); 
	
	/* sanity check on the passed parameters */ 
	if (place < -1 || place > 1)
		return; 
	
	/* fetch the connection */ 
	iConnection = _CGSDefaultConnection(); 
	
	/* carry out operation */
	int i; 
	for (i=0; i<eventTargetsSize; i++) {
		CGSOrderWindow(iConnection, eventTargets[i], place, reference); 
		CGSFlushWindow(iConnection, eventTargets[i], 0); 
	}

	dec_event_order_free(eventOrder); 
}
Exemple #5
0
void DEHandleLevelEvent(DecEvent* event)
{	
	DecEventLevel* eventLevel = dec_event_level_new(event); 
	if (eventLevel == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_level_free(eventLevel); 
		return; 
	}
	
	CGSConnection iConnection; 
	iConnection = _CGSDefaultConnection(); 
	
	int i; 
	OSErr iError; 
	int level = dec_event_level_value_get(eventLevel); 
	
	/* we have to do the list operation on our own, as CGS does not provide an 
	   equivalent */ 
	for (i = 0; i < eventTargetsSize; i++) {
		iError = CGSSetWindowLevel(iConnection, eventTargets[i], &level); 
/* 
		if (iError) 
			printf("DEHandleLevelEvent - CGSSetWindowLevel failed [%i]\n", iError); 
 */ 
	}
	
	dec_event_level_free(eventLevel); 
}
/**
 * Disables or enabled global hot keys.
 *
 * @param   fDisable    Pass 'true' to disable the hot keys, pass 'false' to re-enable them.
 */
void DarwinDisableGlobalHotKeys(bool fDisable)
{
    static unsigned s_cComplaints = 0;

    /*
     * Lazy connect to the core graphics service.
     */
    if (!g_fConnectedToCGS)
    {
        g_CGSConnection = _CGSDefaultConnection();
        g_fConnectedToCGS = true;
    }

    /*
     * Get the current mode.
     */
    CGSGlobalHotKeyOperatingMode enmMode = kCGSGlobalHotKeyInvalid;
    CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmMode);
    if (    enmMode != kCGSGlobalHotKeyEnable
        &&  enmMode != kCGSGlobalHotKeyDisable
        &&  enmMode != kCGSGlobalHotKeyDisableExceptUniversalAccess)
    {
        AssertMsgFailed(("%d\n", enmMode));
        if (s_cComplaints++ < 32)
            LogRel(("DarwinDisableGlobalHotKeys: Unexpected enmMode=%d\n", enmMode));
        return;
    }

    /*
     * Calc the new mode.
     */
    if (fDisable)
    {
        if (enmMode != kCGSGlobalHotKeyEnable)
            return;
        enmMode = kCGSGlobalHotKeyDisable;
    }
    else
    {
        if (enmMode != kCGSGlobalHotKeyDisable)
            return;
        enmMode = kCGSGlobalHotKeyEnable;
    }

    /*
     * Try set it and check the actual result.
     */
    CGSSetGlobalHotKeyOperatingMode(g_CGSConnection, enmMode);
    CGSGlobalHotKeyOperatingMode enmNewMode = kCGSGlobalHotKeyInvalid;
    CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmNewMode);
    if (enmNewMode != enmMode)
    {
        /* If the screensaver kicks in we should ignore failure here. */
        AssertMsg(enmMode == kCGSGlobalHotKeyEnable, ("enmNewMode=%d enmMode=%d\n", enmNewMode, enmMode));
        if (s_cComplaints++ < 32)
            LogRel(("DarwinDisableGlobalHotKeys: Failed to change mode; enmNewMode=%d enmMode=%d\n", enmNewMode, enmMode));
    }
}
uint32_t getMask(int wid) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
	uint32_t mask = 0;
	CGSGetWindowEventMask(cid, wid, &mask);
		
	return mask;
}
void moveWindow(int wid, float x, float y) {
    CGSConnection cid;
    CGPoint point;
    
    cid = _CGSDefaultConnection();
    point.x = x; point.y = y;
    
    CGSMoveWindow(cid, wid, &point);
}
QRect QxtWindowSystem::windowGeometry(WId window)
{
    CGRect rect;
    static CGSConnection connection = _CGSDefaultConnection();

    CGError err = CGSGetWindowBounds(connection, window, &rect);
    if (err != noErr) return QRect();

    return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
void makeUnSticky(int wid) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
	CGSWindowTag tags[2];
	tags[0] = tags[1] = 0;
	OSStatus retVal = CGSGetWindowTags(cid, wid, tags, 32);
	if(!retVal) {
		tags[0] = CGSTagSticky;
		retVal = CGSClearWindowTags(cid, wid, tags, 32);
	}
}
int getTags(int wid) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
	CGSWindowTag tags[2];
	tags[0] = tags[1] = 0;
	CGSGetWindowTags(cid, wid, tags, 32);
	
	// syslog(LOG_WARNING, "Window %x, tags %x%x", wid, tags[1], tags[0]);
	
	return tags[0];
}
void unFadeWindow(int wid) {
    CGSConnection cid;
    float alpha;
	
    cid = _CGSDefaultConnection();
	
	for(alpha=0.0; alpha<=1.0; alpha+=0.05) {
      CGSSetWindowAlpha(cid, wid, alpha);
	  usleep(10000);
	}
	
    CGSSetWindowAlpha(cid, wid, 1.0);
}
void fadeWindow(int wid) {
	float alpha = 0;
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
    //syslog(LOG_ERR, "Fading: %i", wid);
	
	for(alpha=1.0; alpha>=0.0; alpha-=0.05) {
      CGSSetWindowAlpha(cid, wid, alpha);
	  usleep(10000);
	}
	
	CGSSetWindowAlpha(cid, wid, 0.0);
}
Exemple #14
0
void DEHandlePropertyEvent(DecEvent* event)
{
	DecEventProperty* eventProp = dec_event_property_new(event); 
	if (eventProp == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_property_free(eventProp); 
		return; 
	}
	
	char*			key		= dec_event_property_key_get(eventProp); 
	char*			value	= dec_event_property_value_get(eventProp); 
	DecPropertyType	type	= dec_event_property_type_get(eventProp); 
	
	
	CGSValue keyObject		= (int)CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)key);
	CGSValue valueObject	= (int)NULL; 
	if (value)
		valueObject = (int)value;
		valueObject = (int)CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)value);
	
	CGSConnection iConnection = _CGSDefaultConnection(); 
	OSErr iError = noErr; 
	int i; 
	
	/* Have to iterate on our own as there is no CGS equivalent there */ 
	for (i = 0; i < eventTargetsSize; i++) {
		if (type == kDecPropertySet) 
			iError = CGSSetWindowProperty(iConnection, eventTargets[i], keyObject, &valueObject); 
		else
/*			
			CGSDeleteWindowProperty(iConnection, eventTargets[i], keyObject); 
*/
			/* NOP */;
		
		if (iError)
			printf("DEHandlePropertyEvent - Accessing window property failed [%i]\n", iError); 
	}
	
	CGSReleaseGenericObj(&keyObject); 
	if (value)
		CGSReleaseGenericObj(&valueObject); 
}
QString QxtWindowSystem::windowTitle(WId window)
{
    CGSValue windowTitle;
    CGError err(noErr);
    static CGSConnection connection = _CGSDefaultConnection();

    // This code is so dirty I had to wash my hands after writing it.

    // most of CoreGraphics private definitions ask for CGSValue as key but since
    // converting strings to/from CGSValue was dropped in 10.5, I use CFString, which
    // apparently also works.

    // FIXME: Not public API function. Can't compile with OS X 10.8
    // err = CGSGetWindowProperty(connection, window, (CGSValue)CFSTR("kCGSWindowTitle"), &windowTitle);
    if (err != noErr) return QString();

    // this is UTF8 encoded
    return QCFString::toQString((CFStringRef)windowTitle);
}
Exemple #16
0
void DEHandleTagsEvent(DecEvent* event)
{
	DecEventTags* eventTags = dec_event_tags_new(event); 
	if (eventTags == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_tags_free(eventTags); 
		return; 
	}
	
	int i; 
	
	CGSConnection	cgConnection = _CGSDefaultConnection(); 
	CGSWindowTag	cgWindowTags[2] = { 0, 0 };
	
	int					tags = dec_event_tags_value_get(eventTags); 
	DecTagsType	type = dec_event_tags_type_get(eventTags); 
	
	/* I would not feel good about setting the tags for all windows at 
	   once as I do not know what [1] = 0 means for clearing / setting 
	 */ 
  
	for (i = 0; i < eventTargetsSize; i++) {
		OSStatus oResult = CGSGetWindowTags(cgConnection, eventTargets[i], cgWindowTags, 32);
		if (oResult) 
			continue; 
	
		cgWindowTags[0] = tags;
        
		if (type == kDecTagsClear) {
			CGSClearWindowTags( cgConnection, eventTargets[i], cgWindowTags, 32 );
		} else {
			CGSSetWindowTags( cgConnection, eventTargets[i], cgWindowTags, 32 ); 
		}
	}
	
	dec_event_tags_free(eventTags); 
}
Exemple #17
0
void DEHandleDesktopEvent(DecEvent* event) 
{
	DecEventDesktop* desktopEvent = dec_event_desktop_new(event); 
	if (desktopEvent == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_desktop_free(desktopEvent); 
		return; 
	}	
	
	CGSConnection oConnection = _CGSDefaultConnection(); 
	
	/* carry out operation */ 
	CGSMoveWorkspaceWindowList(oConnection, dec_event_targets_get(event), dec_event_targets_size_get(event), dec_event_desktop_value_get(desktopEvent));	
	dec_event_desktop_free(desktopEvent); 
}
WindowList qxt_getWindowsForPSN(ProcessSerialNumber *psn)
{
    static CGSConnection connection = _CGSDefaultConnection();

    WindowList wlist;
    if (!psn) return wlist;

    CGError err(noErr);

    // get onnection for given process psn
    CGSConnection procConnection;
    err = CGSGetConnectionIDForPSN(connection, psn, &procConnection);
    if (err != noErr) return wlist;

    /* get number of windows open by given process
       in Mac OS X an application may have multiple windows, which generally
       represent documents. It is also possible that there is no window even
       though there is an application, it can simply not have any documents open. */

    int windowCount(0);
    err = CGSGetOnScreenWindowCount(connection, procConnection, &windowCount);
    // if there are no windows open by this application, skip
    if (err != noErr || windowCount == 0) return wlist;

    // get list of windows
    int windowList[windowCount];
    int outCount(0);
    err = CGSGetOnScreenWindowList(connection, procConnection, windowCount, windowList, &outCount);

    if (err != noErr || outCount == 0) return wlist;

    for (int i=0; i<outCount; ++i)
    {
        wlist += windowList[i];
    }

    return wlist;
}
Exemple #19
0
stubGetWindowInfo( Display *dpy, GLXDrawable drawable )
#endif
{
    WindowInfo *winInfo = (WindowInfo *) crHashtableSearch(stub.windowTable, (unsigned int) drawable);
    if (!winInfo) {
	winInfo = (WindowInfo *) crCalloc(sizeof(WindowInfo));
	if (!winInfo)
	    return NULL;
#ifdef GLX
	crStrncpy(winInfo->dpyName, DisplayString(dpy), MAX_DPY_NAME);
	winInfo->dpyName[MAX_DPY_NAME-1] = 0;
	winInfo->dpy = dpy;
#elif defined(Darwin)
	winInfo->connection = _CGSDefaultConnection(); // store our connection as default
#endif
	winInfo->drawable = drawable;
	winInfo->type = UNDECIDED;
	winInfo->spuWindow = -1;
	winInfo->mapped = -1; /* don't know */
	crHashtableAdd(stub.windowTable, (unsigned int) drawable, winInfo);
    }
    return winInfo;
}
void orderOutWindow(int wid) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
    CGSOrderWindow(cid, wid, kCGSOrderOut, 0);
}
void moveToWorkspace(int wid, int workspace) {
	CGSConnection cid;

	cid = _CGSDefaultConnection();
	CGSMoveWorkspaceWindowList(cid,&wid,1,workspace);
}
stubGetWindowInfo( Display *dpy, GLXDrawable drawable )
#endif
{
#ifndef WINDOWS
    WindowInfo *winInfo = (WindowInfo *) crHashtableSearch(stub.windowTable, (unsigned int) drawable);
#else
    WindowInfo *winInfo;
    HWND hwnd;
    hwnd = WindowFromDC(drawable);

    if (!hwnd)
    {
        return NULL;
    }

    winInfo = (WindowInfo *) crHashtableSearch(stub.windowTable, (unsigned int) hwnd);
#endif
    if (!winInfo) {
    winInfo = (WindowInfo *) crCalloc(sizeof(WindowInfo));
    if (!winInfo)
        return NULL;
#ifdef GLX
    crStrncpy(winInfo->dpyName, DisplayString(dpy), MAX_DPY_NAME);
    winInfo->dpyName[MAX_DPY_NAME-1] = 0;
    winInfo->dpy = dpy;
    winInfo->pVisibleRegions = NULL;
#elif defined(Darwin)
    winInfo->connection = _CGSDefaultConnection(); // store our connection as default
#elif defined(WINDOWS)
    winInfo->hVisibleRegion = INVALID_HANDLE_VALUE;
    winInfo->hWnd = hwnd;
#endif
    winInfo->drawable = drawable;
    winInfo->type = UNDECIDED;
    winInfo->spuWindow = -1;
#ifdef VBOX_WITH_WDDM
    if (stub.bRunningUnderWDDM)
        winInfo->mapped = 0;
    else
#endif
    {
        winInfo->mapped = -1; /* don't know */
    }
    winInfo->pOwner = NULL;
#ifdef CR_NEWWINTRACK
    winInfo->u32ClientID = -1;
#endif
#ifndef WINDOWS
    crHashtableAdd(stub.windowTable, (unsigned int) drawable, winInfo);
#else
    crHashtableAdd(stub.windowTable, (unsigned int) hwnd, winInfo);
#endif
    }
#ifdef WINDOWS
    else
    {
        winInfo->drawable = drawable;
    }
#endif
    return winInfo;
}
Exemple #23
0
void macosxCGS_get_all_windows(void) {
	static double last = 0.0;
	static int totcnt = 0;
	double dt = 0.0, now = dnow();
	int i, db = 0, whist_prv = 0, maxwin = 0, whist_skip = 0;
	CGSWindowCount cap = (CGSWindowCount) MAXWINDAT;
	CGSError err; 

	CGS_levelmax = 0;
	CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel;	/* 500 ? */
	if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel;		/* 102 ? */
	if (macosx_ncache_macmenu) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel;	/* 101 pulldown menu */
	CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey;	/*  24 ? */
	CGS_levels[CGS_levelmax++] = (int) kCGModalPanelWindowLevel;	/*   8 open dialog box */
	CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel;	/*   3 ? */
	CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel;	/*   0 regular window */

	if (cid == NULL) {
		cid = _CGSDefaultConnection();
		if (cid == NULL) {
			return;
		}
	}

	if (dt > 0.0 && now < last + dt) {
		return;
	}

	last = now;

	macwinmax = 0; 

	totcnt++;

	if (ncache > 0) {
		whist_prv = whist_idx++;
		if (whist_prv < 0) {
			whist_skip = 1;
			whist_prv = 0;
		}
		whist_idx = whist_idx % WINHISTMAX;
		for (i=0; i < WINHISTNUM; i++) {
			whist[whist_idx][i] = 0;
			qlook[i] = -1;
		}
	}

	err = CGSGetWindowList(cid, NULL, cap, _wins_all, &_wins_all_cnt);

if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_all_cnt, err);

	if (err != 0) {
		return;
	}
	
	for (i=0; i < (int) _wins_all_cnt; i++) {
		CGSRect rect;
		CGSWindowLevel level;
		int j, keepit = 0;
		err = CGSGetScreenRectForWindow(cid, _wins_all[i], &rect);
		if (err != 0) {
			continue;
		}
		if (rect.origin.x == 0 && rect.origin.y == 0) {
			if (rect.size.width == dpy_x) {
				if (rect.size.height == dpy_y) {
					continue;
				}
			}
		}
		err = CGSGetWindowLevel(cid, _wins_all[i], &level);
		if (err != 0) {
			continue;
		}
		for (j=0; j<CGS_levelmax; j++) {
			if ((int) level == CGS_levels[j]) {
				keepit = 1;
				break;
			}
		}
		if (! keepit) {
			continue;
		}

		macwins[macwinmax].level  = (int) level;
		macwins[macwinmax].win    = (int) _wins_all[i];
		macwins[macwinmax].x      = (int) rect.origin.x;
		macwins[macwinmax].y      = (int) rect.origin.y;
		macwins[macwinmax].width  = (int) rect.size.width;
		macwins[macwinmax].height = (int) rect.size.height;
		macwins[macwinmax].mapped = 0;
		macwins[macwinmax].clipped = 0;
		macwins[macwinmax].ncache_only = 0;
		if (level == kCGPopUpMenuWindowLevel) {
			macwins[macwinmax].ncache_only = 1;
		}

if (0 || db) fprintf(stderr, "i=%03d ID: %06d  x: %03d  y: %03d  w: %03d h: %03d level: %d\n", i, _wins_all[i],
    (int) rect.origin.x, (int) rect.origin.y,(int) rect.size.width, (int) rect.size.height, (int) level);

		if (macwins[macwinmax].win < WINHISTNUM) {
			qlook[macwins[macwinmax].win] = macwinmax;
			if (macwins[macwinmax].win > maxwin) {
				maxwin = macwins[macwinmax].win;
			}
		}

		macwinmax++;
	}

	err = CGSGetOnScreenWindowList(cid, NULL, cap, _wins_mapped, &_wins_mapped_cnt);

if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_mapped_cnt, err);

	if (err != 0) {
		return;
	}
	
	for (i=0; i < (int) _wins_mapped_cnt; i++) {
		int j, idx = -1;
		int win = (int) _wins_mapped[i];

		if (0 <= win && win < WINHISTNUM) {
			j = qlook[win];
			if (j >= 0 && macwins[j].win == win) {
				idx = j; 
			}
		}
		if (idx < 0) {
			for (j=0; j < macwinmax; j++) {
				if (macwins[j].win == win) {
					idx = j; 
					break;
				}
			}
		}
		if (idx >= 0) {
			macwins[idx].mapped = 1;
		}
	}

	if (ncache > 0) {
		int nv= 0, NBMAX = 64;
		int nv_win[64];
		int nv_lvl[64];
		int nv_vis[64];

		for (i=0; i < macwinmax; i++) {
			int win = macwins[i].win;
			char prev, curr;

			if (win >= WINHISTNUM) {
				continue;
			}

			whist[whist_idx][win] |= is_exist;
			if (macwins[i].mapped) {
				whist[whist_idx][win] |= is_mapped;
				if (check_clipped(win)) {
					whist[whist_idx][win] |= is_clipped;
					macwins[i].clipped = 1;
				}
				if (check_offscreen(win)) {
					whist[whist_idx][win] |= is_offscreen;
				}
			} else {
				whist[whist_idx][win] |= is_offscreen;
			}

			curr = whist[whist_idx][win];
			prev = whist[whist_prv][win];

			if (whist_skip) {
				;
			} else if ( !(prev & is_mapped) && (curr & is_mapped)) {
				/* MapNotify */
				if (0) fprintf(stderr, "MapNotify:   %d/%d  %d               %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 
				macosx_add_mapnotify(win, macwins[i].level, 1);
				if (0) macosxCGS_follow_animation_win(win, i, 1);

			} else if ( !(curr & is_mapped) && (prev & is_mapped)) {
				/* UnmapNotify */
				if (0) fprintf(stderr, "UnmapNotify: %d/%d  %d               %.4f A tot=%d\n", prev, curr, win, dnowx(), totcnt); 
				macosx_add_mapnotify(win, macwins[i].level, 0);
			} else if ( !(prev & is_exist) && (curr & is_exist)) {
				/* CreateNotify */
				if (0) fprintf(stderr, "CreateNotify:%d/%d  %d               %.4f whist: %d/%d 0x%x tot=%d\n", prev, curr, win, dnowx(), whist_prv, whist_idx, win, totcnt); 
				macosx_add_create(win, macwins[i].level);
				if (curr & is_mapped) {
					if (0) fprintf(stderr, "MapNotify:   %d/%d  %d               %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 
					macosx_add_mapnotify(win, macwins[i].level, 1);
				}
			}
			if (whist_skip) {
				;
			} else if (nv >= NBMAX) {
				;
			} else if (!(curr & is_mapped)) {
				;
			} else if (!(prev & is_mapped)) {
				if (1) {
					;
				} else if (curr & is_clipped) {
					if (0) fprintf(stderr, "VisibNotify: %d/%d  %d               OBS tot=%d\n", prev, curr, win, totcnt); 
					nv_win[nv] = win;
					nv_lvl[nv] = macwins[i].level;
					nv_vis[nv++] = 1;
				} else {
					if (0) fprintf(stderr, "VisibNotify: %d/%d  %d               UNOBS tot=%d\n", prev, curr, win, totcnt); 
					nv_win[nv] = win;
					nv_lvl[nv] = macwins[i].level;
					nv_vis[nv++] = 0;
				}
			} else {
				if        ( !(prev & is_clipped) &&  (curr & is_clipped) ) {
					if (0) fprintf(stderr, "VisibNotify: %d/%d  %d               OBS tot=%d\n", prev, curr, win, totcnt); 
					nv_win[nv] = win;
					nv_lvl[nv] = macwins[i].level;
					nv_vis[nv++] = 1;
				} else if (  (prev & is_clipped) && !(curr & is_clipped) ) {
					if (0) fprintf(stderr, "VisibNotify: %d/%d  %d               UNOBS tot=%d\n", prev, curr, win, totcnt); 
					nv_win[nv] = win;
					nv_lvl[nv] = macwins[i].level;
					nv_vis[nv++] = 0;
				}
			}
		}
		for (i=0; i < maxwin; i++) {
			char prev, curr;
			int win = i;
			int q = qlook[i];
			int lvl = 0;

			if (whist_skip) {
				break;
			}

			if (q >= 0) {
				lvl = macwins[q].level;	
			}
			curr = whist[whist_idx][win];
			prev = whist[whist_prv][win];
			if (!(curr & is_exist) && (prev & is_exist)) {
				if (prev & is_mapped) {
					if (0) fprintf(stderr, "UnmapNotify: %d/%d  %d               %.4f B tot=%d\n", prev, curr, win, dnowx(), totcnt); 
					macosx_add_mapnotify(win, lvl, 0);
				}
				/* DestroyNotify */
				if (0) fprintf(stderr, "DestroNotify:%d/%d  %d               %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 
				macosx_add_destroy(win, lvl);
			}
		}
		if (nv) {
			int k;
			for (k = 0; k < nv; k++) {
				macosx_add_visnotify(nv_win[k], nv_lvl[k], nv_vis[k]);
			}
		}
	}
}
void hideWindow(int wid) {
	CGSConnection cid;
	
	cid = _CGSDefaultConnection();
	CGSSetWindowAlpha(cid, wid, 0.0);
}
void showWindow(int wid) {
	CGSConnection cid;
	
	cid = _CGSDefaultConnection();
	CGSSetWindowAlpha(cid, wid, 1.0);
}
PsychError SCREENGetWindowInfo(void) 
{
    const char *FieldNames[]={ "Beamposition", "LastVBLTimeOfFlip", "LastVBLTime", "VBLCount", "TimeAtSwapRequest", "TimePostSwapRequest", "RawSwapTimeOfFlip",
							   "VBLTimePostFlip", "OSSwapTimestamp", "GPULastFrameRenderTime", "StereoMode", "ImagingMode", "MultiSampling", "MissedDeadlines", "FlipCount", "StereoDrawBuffer",
							   "GuesstimatedMemoryUsageMB", "VBLStartline", "VBLEndline", "VideoRefreshFromBeamposition", "GLVendor", "GLRenderer", "GLVersion", "GPUCoreId", 
							   "GLSupportsFBOUpToBpc", "GLSupportsBlendingUpToBpc", "GLSupportsTexturesUpToBpc", "GLSupportsFilteringUpToBpc", "GLSupportsPrecisionColors",
							   "GLSupportsFP32Shading", "BitsPerColorComponent", "IsFullscreen", "SpecialFlags", "SwapGroup", "SwapBarrier" };
							   
	const int  fieldCount = 35;
	PsychGenericScriptType	*s;

    PsychWindowRecordType *windowRecord;
    double beamposition, lastvbl;
	int infoType = 0, retIntArg;
	double auxArg1, auxArg2, auxArg3;
	CGDirectDisplayID displayId;
	psych_uint64 postflip_vblcount;
	double vbl_startline;
	long scw, sch;
	psych_bool onscreen;
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(5));     //The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); //The required number of inputs	
    PsychErrorExit(PsychCapNumOutputArgs(1));    //The maximum number of outputs

    // Query infoType flag: Defaults to zero.
    PsychCopyInIntegerArg(2, FALSE, &infoType);
	if (infoType < 0 || infoType > 5) PsychErrorExitMsg(PsychError_user, "Invalid 'infoType' argument specified! Valid are 0, 1, 2, 3, 4 and 5.");

	// Windowserver info requested?
	if (infoType == 2 || infoType == 3) {
		// Return info about WindowServer:
		#if PSYCH_SYSTEM == PSYCH_OSX

		const char *CoreGraphicsFieldNames[]={ "CGSFps", "CGSValue1", "CGSValue2", "CGSValue3", "CGSDebugOptions" };
		const int CoreGraphicsFieldCount = 5;
		float cgsFPS, val1, val2, val3;
		
		// This (undocumented) Apple call retrieves information about performance statistics of
		// the Core graphics server, also known as WindowServer or Quartz compositor:
		CGSGetPerformanceData(_CGSDefaultConnection(), &cgsFPS, &val1, &val2, &val3);
		if (CGSGetDebugOptions(&retIntArg)) {
			if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSGetDebugOptions() failed!\n");
		}
		
		PsychAllocOutStructArray(1, FALSE, 1, CoreGraphicsFieldCount, CoreGraphicsFieldNames, &s);
		PsychSetStructArrayDoubleElement("CGSFps", 0   , cgsFPS, s);
		PsychSetStructArrayDoubleElement("CGSValue1", 0, val1, s);
		PsychSetStructArrayDoubleElement("CGSValue2", 0, val2, s);
		PsychSetStructArrayDoubleElement("CGSValue3", 0, val3, s);
		PsychSetStructArrayDoubleElement("CGSDebugOptions", 0, (double) retIntArg, s);
		
		if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) ) {
			// Type 3 setup request with auxArg1 provided. Apple auxArg1 as debugFlag setting
			// for the CoreGraphics server: DANGEROUS!
			if (CGSSetDebugOptions((unsigned int) auxArg1)) {
				if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSSetDebugOptions() failed!\n");
			}
		}

		#endif
		
		#if PSYCH_SYSTEM == PSYCH_WINDOWS
		psych_uint64 onsetVBLCount, frameId;
		double onsetVBLTime, compositionRate;
		psych_uint64 targetVBL;
		
		PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
		// Query all DWM presentation timing info, return full info as struct in optional return argument '1':
		if (PsychOSGetPresentationTimingInfo(windowRecord, TRUE, 0, &onsetVBLCount, &onsetVBLTime, &frameId, &compositionRate, 1)) {
			// Query success: Info struct has been created and returned by PsychOSGetPresentationTimingInfo()...
			auxArg1 = auxArg2 = 0;
			auxArg3 = 2;
			
			// Want us to change settings?
			if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) && PsychCopyInDoubleArg(4, FALSE, &auxArg2) && PsychCopyInDoubleArg(5, FALSE, &auxArg3)) {
				if (auxArg1 < 0) auxArg1 = 0;
				targetVBL = auxArg1;
				if (PsychOSSetPresentParameters(windowRecord, targetVBL, (int) auxArg3, auxArg2)) {
					if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: GetWindowInfo: Call to PsychOSSetPresentParameters(%i, %i, %f) SUCCESS!\n", (int) auxArg1, (int) auxArg3, auxArg2);
				}
				else {
					if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to PsychOSSetPresentParameters() failed!\n");
				}
			}
		}
		else {
			// Unsupported / Failed:
			PsychCopyOutDoubleArg(1, FALSE, -1);
		}

		#endif

		#if PSYCH_SYSTEM == PSYCH_LINUX
			if (infoType == 2) {
				// MMIO register Read for screenid "auxArg1", register offset "auxArg2":
				PsychCopyInDoubleArg(3, TRUE, &auxArg1);
				PsychCopyInDoubleArg(4, TRUE, &auxArg2);
				PsychCopyOutDoubleArg(1, FALSE, (double) PsychOSKDReadRegister((int) auxArg1, (unsigned int) auxArg2, NULL));
			}
			
			if (infoType == 3) {
				// MMIO register Write for screenid "auxArg1", register offset "auxArg2", to value "auxArg3":
				PsychCopyInDoubleArg(3, TRUE, &auxArg1);
				PsychCopyInDoubleArg(4, TRUE, &auxArg2);
				PsychCopyInDoubleArg(5, TRUE, &auxArg3);
				PsychOSKDWriteRegister((int) auxArg1, (unsigned int) auxArg2, (unsigned int) auxArg3, NULL);
			}
		#endif

		// Done.
		return(PsychError_none);
	}

    // Get the window record:
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	onscreen = PsychIsOnscreenWindow(windowRecord);

	if (onscreen) {
		// Query rasterbeam position: Will return -1 if unsupported.
		PsychGetCGDisplayIDFromScreenNumber(&displayId, windowRecord->screenNumber);
		beamposition = (double) PsychGetDisplayBeamPosition(displayId, windowRecord->screenNumber);
	}
	else {
		beamposition = -1;
	}
	
	if (infoType == 1) {
		// Return the measured beamposition:
		PsychCopyOutDoubleArg(1, FALSE, beamposition);
	}
    else if (infoType == 4) {
        // Return async flip state: 1 = Active, 0 = Inactive.
        PsychCopyOutDoubleArg(1, FALSE, (((NULL != windowRecord->flipInfo) && (0 != windowRecord->flipInfo->asyncstate)) ? 1 : 0));
    }
	else if (infoType == 5) {
		// Create a GL_EXT_timer_query object for this window:
		if (glewIsSupported("GL_EXT_timer_query")) {
			// Pending queries finished?
			if (windowRecord->gpuRenderTimeQuery > 0) {
				PsychErrorExitMsg(PsychError_user, "Tried to create a new GPU rendertime query, but last query not yet finished! Call Screen('Flip') first!");
			}
			
			// Enable our rendering context by selecting this window as drawing target:
			PsychSetDrawingTarget(windowRecord);
			
			// Generate Query object:
			glGenQueries(1, &windowRecord->gpuRenderTimeQuery);
			
			// Emit Query: GPU will measure elapsed processing time in Nanoseconds, starting
			// with the first GL command executed after this command:
			glBeginQuery(GL_TIME_ELAPSED_EXT, windowRecord->gpuRenderTimeQuery);
			
			// Reset last measurement:
			windowRecord->gpuRenderTime = 0;
		}
		else {
			if (PsychPrefStateGet_Verbosity() > 4) printf("PTB-INFO: GetWindowInfo for infoType 5: GPU timer query objects are unsupported on this platform and GPU. Call ignored!\n");
		}
	}
	else {
		// Return all information:
		PsychAllocOutStructArray(1, FALSE, 1, fieldCount, FieldNames, &s);

		// Rasterbeam position:
		PsychSetStructArrayDoubleElement("Beamposition", 0, beamposition, s);

		// Time of last vertical blank when a double-buffer swap occured:
		if ((windowRecord->flipCount > 0) && (windowRecord->time_at_last_vbl == 0) && (PsychPrefStateGet_VBLTimestampingMode() == 4)) {
			// If time_at_last_vbl for an already finished or at least pending flip isn't available and
			// we have support for OS-Builtin timestamping enabled, we try to employ OS-Builtin timestamping
			// to get a timestamp for the most recent pending or finished flip. If this fails or is unsupported,
			// it will have no effect:
			PsychOSGetSwapCompletionTimestamp(windowRecord, 0, &(windowRecord->time_at_last_vbl));
		}

		// Return it - or the value zero if it is (still) undefined/unavailable:
		PsychSetStructArrayDoubleElement("LastVBLTimeOfFlip", 0, windowRecord->time_at_last_vbl, s);

		// Uncorrected timestamp of flip swap completion:
		PsychSetStructArrayDoubleElement("RawSwapTimeOfFlip", 0, windowRecord->rawtime_at_swapcompletion, s);

		// Timestamp immediately prior to call to PsychOSFlipWindowBuffers(), i.e., time at swap request submission:
		PsychSetStructArrayDoubleElement("TimeAtSwapRequest", 0, windowRecord->time_at_swaprequest, s);

		// Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
		PsychSetStructArrayDoubleElement("TimePostSwapRequest", 0, windowRecord->time_post_swaprequest, s);

		// Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
		PsychSetStructArrayDoubleElement("VBLTimePostFlip", 0, windowRecord->postflip_vbltimestamp, s);

		// Swap completion timestamp for most recently completed swap, according to OS-builtin PsychOSGetSwapCompletionTimestamp() method:
		PsychSetStructArrayDoubleElement("OSSwapTimestamp", 0, windowRecord->osbuiltin_swaptime, s);

		// Result from last GPU rendertime query as triggered by infoType 5: Zero if undefined.
		PsychSetStructArrayDoubleElement("GPULastFrameRenderTime", 0, windowRecord->gpuRenderTime, s);

		// Try to determine system time of last VBL on display, independent of any
		// flips / bufferswaps.
		lastvbl = -1;
		postflip_vblcount = 0;
		
		// On supported systems, we can query the OS for the system time of last VBL, so we can
		// use the most recent VBL timestamp as baseline for timing calculations, 
		// instead of one far in the past.
		if (onscreen) { lastvbl = PsychOSGetVBLTimeAndCount(windowRecord, &postflip_vblcount); }

		// If we couldn't determine this information we just set lastvbl to the last known
		// vbl timestamp of last flip -- better than nothing...
		if (lastvbl < 0) lastvbl = windowRecord->time_at_last_vbl;
		PsychSetStructArrayDoubleElement("LastVBLTime", 0, lastvbl, s);
		PsychSetStructArrayDoubleElement("VBLCount", 0, (double) (psych_int64) postflip_vblcount, s);
        
		// Misc. window parameters:
		PsychSetStructArrayDoubleElement("StereoMode", 0, windowRecord->stereomode, s);
		PsychSetStructArrayDoubleElement("ImagingMode", 0, windowRecord->imagingMode, s);
		PsychSetStructArrayDoubleElement("SpecialFlags", 0, windowRecord->specialflags, s);
		PsychSetStructArrayDoubleElement("IsFullscreen", 0, (windowRecord->specialflags & kPsychIsFullscreenWindow) ? 1 : 0, s);
		PsychSetStructArrayDoubleElement("MultiSampling", 0, windowRecord->multiSample, s);
		PsychSetStructArrayDoubleElement("MissedDeadlines", 0, windowRecord->nr_missed_deadlines, s);
		PsychSetStructArrayDoubleElement("FlipCount", 0, windowRecord->flipCount, s);
		PsychSetStructArrayDoubleElement("StereoDrawBuffer", 0, windowRecord->stereodrawbuffer, s);
		PsychSetStructArrayDoubleElement("GuesstimatedMemoryUsageMB", 0, (double) windowRecord->surfaceSizeBytes / 1024 / 1024, s);
		PsychSetStructArrayDoubleElement("BitsPerColorComponent", 0, (double) windowRecord->bpc, s);
		
		// Query real size of the underlying display in order to define the vbl_startline:
		PsychGetScreenSize(windowRecord->screenNumber, &scw, &sch);
		vbl_startline = (double) sch;
		PsychSetStructArrayDoubleElement("VBLStartline", 0, vbl_startline, s);

		// And VBL endline:
		PsychSetStructArrayDoubleElement("VBLEndline", 0, windowRecord->VBL_Endline, s);

		// Video refresh interval duration from beamposition method:
		PsychSetStructArrayDoubleElement("VideoRefreshFromBeamposition", 0, windowRecord->ifi_beamestimate, s);
    
		// Swap group assignment and swap barrier assignment, if any:
		PsychSetStructArrayDoubleElement("SwapGroup", 0, windowRecord->swapGroup, s);
		PsychSetStructArrayDoubleElement("SwapBarrier", 0, windowRecord->swapBarrier, s);
	
        // Which basic GPU architecture is this?
		PsychSetStructArrayStringElement("GPUCoreId", 0, windowRecord->gpuCoreId, s);
		
		// FBO's supported, and how deep?
		if (windowRecord->gfxcaps & kPsychGfxCapFBO) {
			if (windowRecord->gfxcaps & kPsychGfxCapFPFBO32) {
				PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 32, s);
			} else
			if (windowRecord->gfxcaps & kPsychGfxCapFPFBO16) {
				PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 16, s);
			} else PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 8, s);
		}
		else {
			PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 0, s);
		}

		// How deep is alpha blending supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPBlend32) {
			PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPBlend16) {
			PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 8, s);
		
		// How deep is texture mapping supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPTex32) {
			PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPTex16) {
			PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 8, s);
		
		// How deep is texture filtering supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPFilter32) {
			PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPFilter16) {
			PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 8, s);

		if (windowRecord->gfxcaps & kPsychGfxCapVCGood) {
			PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 1, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 0, s);

		if (windowRecord->gfxcaps & kPsychGfxCapFP32Shading) {
			PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 1, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 0, s);

		// Renderer information: This comes last, and would fail if async flips
        // are active, because it needs PsychSetDrawingTarget, which in turn needs async
        // flips to be inactive:
        PsychSetDrawingTarget(windowRecord);
        PsychSetStructArrayStringElement("GLVendor", 0, (char*) glGetString(GL_VENDOR), s);
        PsychSetStructArrayStringElement("GLRenderer", 0, (char*) glGetString(GL_RENDERER), s);
        PsychSetStructArrayStringElement("GLVersion", 0, (char*) glGetString(GL_VERSION), s);
    }
    
    // Done.
    return(PsychError_none);
}
Exemple #27
0
void DEHandleAlphaEvent(DecEvent* event)
{
	DecEventAlpha* eventAlpha = dec_event_alpha_new(event); 
	if (eventAlpha == NULL)
		return; 
	
	int* eventTargets		= dec_event_targets_get(event); 
	int	 eventTargetsSize	= dec_event_targets_size_get(event); 
	
	if (eventTargets == NULL || eventTargetsSize == 0) {
		dec_event_alpha_free(eventAlpha); 
		return; 
	}
	
	float eventStartValue	= dec_event_alpha_startvalue_get(eventAlpha);
	float eventEndValue		= dec_event_alpha_endvalue_get(eventAlpha);
	float animateSeconds	= dec_event_alpha_duration_get(eventAlpha);
	
	/* @todo Implement animation parameter */ 
	CGSConnection iConnection;
	
	/* Correct input parameter ranges */ 
	if (eventEndValue < 0.0)
		eventEndValue = 0.0; 
	if (eventEndValue > 1.0)
		eventEndValue = 1.0;
	
	if (eventStartValue < 0.0)
		eventStartValue = 0.0; 
	if (eventStartValue > 1.0)
		eventStartValue = 1.0;

	
	/* Get the default connection for our process */ 
	iConnection = _CGSDefaultConnection(); 
	
	if (animateSeconds == 0) {
		CGSSetWindowListAlpha(iConnection, eventTargets, eventTargetsSize, eventEndValue);
	} else {
		/* Animate */
		CGSSetWindowListAlpha(iConnection, eventTargets, eventTargetsSize, eventEndValue);
// Not ready yet
//		if ( eventStartValue > eventEndValue) {
//			for (eventStartValue; eventStartValue <= eventEndValue; eventEndValue += 0.05) {
//				CGSSetWindowListAlpha(iConnection, eventTargets, eventTargetsSize, eventEndValue);
//				usleep(10000);
//			}
//		} else if ( eventStartValue < eventEndValue ) {
//			for (eventStartValue; eventStartValue >= eventEndValue; eventEndValue -= 0.05) {
//				CGSSetWindowListAlpha(iConnection, eventTargets, eventTargetsSize, eventEndValue);
//				usleep(10000);
//			}
//		} else {
//			CGSSetWindowListAlpha(iConnection, eventTargets, eventTargetsSize, eventEndValue);
//		}
		
	}
	
	
	 
	
	/* get rid of the event */ 
	dec_event_alpha_free(eventAlpha); 
}
void setMask(int wid, uint32_t mask) {
    CGSConnection cid;
    
    cid = _CGSDefaultConnection();
	syslog(LOG_WARNING, "RetVal: %i", CGSSetWindowEventMask(cid, wid, mask));
}
Exemple #29
0
int macosxCGS_follow_animation_win(int win, int idx, int grow) {
	double t = dnow();
	int diffs = 0;
	int x, y, w, h;
	int xp = -1, yp = -1, wp = -1, hp = -1;
	CGSRect rect;
	CGSError err; 

	int reps = 0;

	if (cid == NULL) {
		cid = _CGSDefaultConnection();
		if (cid == NULL) {
			return 0;
		}
	}

	if (idx < 0) {
		idx = macosxCGS_find_index(win); 
	}
	if (idx < 0) {
		return 0;
	}

	while (dnow() < t + 0.001 * macosx_icon_anim_time)  {
		err = CGSGetScreenRectForWindow(cid, win, &rect);
		if (err != 0) {
			break;
		}
		x = (int) rect.origin.x;
		y = (int) rect.origin.y;
		w = (int) rect.size.width;
		h = (int) rect.size.height;

		if (grow) {
			macwins[idx].x      = x;
			macwins[idx].y      = y;
			macwins[idx].width  = w;
			macwins[idx].height = h;
		}
	
		if (0) fprintf(stderr, " chase: %03dx%03d+%03d+%03d  %d\n", w, h, x, y, win);
		if (x == xp && y == yp && w == wp && h == hp)  {
			reps++;
			if (reps >= 2) {
				break;
			}
		} else {
			diffs++;
			reps = 0;
		}
		xp = x;
		yp = y;
		wp = w;
		hp = h;
		usleep(50 * 1000);
	}
	if (diffs >= 2) {
		return 1;
	} else {
		return 0;
	}
}