view src/thread/bsdi/SDL_syssem.c @ 1192:54aa9aa32327

To: sdl@libsdl.org From: Christian Walther <cwalther@gmx.ch> Date: Fri, 18 Nov 2005 23:39:02 +0100 Subject: [SDL] Mouse position bugs on Mac OS X The attached patch fixes a few bugs in SDL related to the mouse position in windowed mode on Mac OS X, reproduced using the attached minimal test program - at least here on 10.3.9, with SDL CVS from today. Could anyone test whether the bugs exist and are fixed by the patch on 10.2 and 10.4? 1. When using OpenGL, the vertical mouse positions obtained through events or SDL_GetMouseState() are off by one. 2. When using OpenGL, SDL_WarpMouse() inverts the y coordinate. 3. Clicks on the topmost pixel row of the window are not recognized. 1 and 2 do not occur in non-OpenGL mode, while 3 does. All three only occur in windowed mode, not in fullscreen. The cause for 1 and 3 is that in Cocoa, "the location of the mouse" seems to be defined as "the location of the top left corner of the mouse pointer's hot pixel" (this is not documented, it's just what I found out here), which together with the fact that Cocoa's usual y coordinates start at the bottom and increase upwards means that the y coordinate of the mouse runs from 1 to h, not from 0 to h-1, in a window of height h. If it does work on 10.2 and 10.4 (I'll try to test it as soon as I can, but at the moment all I have at hand is 10.3.9), can this be applied to the CVS? -Christian To: sdl@libsdl.org From: Christian Walther <cwalther@gmx.ch> Date: Mon, 28 Nov 2005 10:41:51 +0100 Subject: [SDL] Re: Mouse position bugs on Mac OS X I wrote: > I'll try to test it as soon as I can, but at the moment all I have at hand is 10.3.9 So, here are the results of my tests (with patched and unpatched frameworks compiled with Xcode 1.5 (gcc 3.3) on 10.3.9): On 10.1.5, my test program doesn't run because of "Undefined symbols: SDL undefined reference to _CGMainDisplayID expected to be defined in Carbon". I guess not supporting 10.1 was a deliberate decision then and that's OK with me. On 10.2.8, 10.3.9, and 10.4.0, the bugs exist as described in my original post and are fixed by my patch. That is, there is no difference between pre/post 10.3 and the patched version works correctly in all combinations of GL/non-GL and windowed/fullscreen. I therefore recommend the patch for inclusion. -Christian
author Ryan C. Gordon <icculus@icculus.org>
date Mon, 28 Nov 2005 13:58:26 +0000
parents b8d311d90021
children c9b51268668f
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2004 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Sam Lantinga
    slouken@devolution.com
*/

#ifdef SAVE_RCSID
static char rcsid =
 "@(#) $Id$";
#endif

#include <stdlib.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_timer.h"

#ifdef SDL_USE_PTHREADS

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>			/* For getpid() */
#include <pthread.h>


/*
 * This is semaphore.h inlined here so that BSD/OS POSIX semaphore are
 * completely selfcontained without requiring any additional include files
 * or libraries not present in the stock system
*/

/* semaphore.h: POSIX 1003.1b semaphores */

/*-
 * Copyright (c) 1996, 1997
 *	HD Associates, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by HD Associates, Inc
 * 4. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/sys/posix4/semaphore.h,v 1.6 2000/01/20 07:55:42 jasone Exp $
 */

#include <machine/limits.h>

#include <sys/types.h>
#include <fcntl.h>

/* Opaque type definition. */
struct sem;
typedef struct sem *sem_t;

#define SEM_FAILED	((sem_t *)0)
#define SEM_VALUE_MAX	UINT_MAX

#include <sys/cdefs.h>

__BEGIN_DECLS
int	 sem_init __P((sem_t *, int, unsigned int));
int	 sem_destroy __P((sem_t *));
sem_t	*sem_open __P((const char *, int, ...));
int	 sem_close __P((sem_t *));
int	 sem_unlink __P((const char *));
int	 sem_wait __P((sem_t *));
int	 sem_trywait __P((sem_t *));
int	 sem_post __P((sem_t *));
int	 sem_getvalue __P((sem_t *, int *));
__END_DECLS

/* END of inlined semaphore.h */

/* Wrapper around POSIX 1003.1b semaphores */

struct SDL_semaphore {
	sem_t *sem;
	sem_t sem_data;
};

/* Create a semaphore, initialized with value */
SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
{
	SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem));
	if ( sem ) {
		if ( sem_init(&sem->sem_data, 0, initial_value) < 0 ) {
			SDL_SetError("sem_init() failed");
			free(sem);
			sem = NULL;
		} else {
			sem->sem = &sem->sem_data;
		}
	} else {
		SDL_OutOfMemory();
	}
	return sem;
}

void SDL_DestroySemaphore(SDL_sem *sem)
{
	if ( sem ) {
		sem_destroy(sem->sem);
		free(sem);
	}
}

int SDL_SemTryWait(SDL_sem *sem)
{
	int retval;

	if ( ! sem ) {
		SDL_SetError("Passed a NULL semaphore");
		return -1;
	}
	retval = SDL_MUTEX_TIMEDOUT;
	if ( sem_trywait(sem->sem) == 0 )
		retval = 0;
	return retval;
}

int SDL_SemWait(SDL_sem *sem)
{
	int retval;

	if ( ! sem ) {
		SDL_SetError("Passed a NULL semaphore");
		return -1;
	}

	retval = sem_wait(sem->sem);
	if ( retval < 0 ) {
		SDL_SetError("sem_wait() failed");
	}
	return retval;
}

int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
{
	int retval;

	if ( ! sem ) {
		SDL_SetError("Passed a NULL semaphore");
		return -1;
	}

	/* Try the easy cases first */
	if ( timeout == 0 ) {
		return SDL_SemTryWait(sem);
	}
	if ( timeout == SDL_MUTEX_MAXWAIT ) {
		return SDL_SemWait(sem);
	}

	/* Ack!  We have to busy wait... */
	timeout += SDL_GetTicks();
	do {
		retval = SDL_SemTryWait(sem);
		if ( retval == 0 ) {
			break;
		}
		SDL_Delay(1);
	} while ( SDL_GetTicks() < timeout );

	return retval;
}

Uint32 SDL_SemValue(SDL_sem *sem)
{
	int ret = 0;
	if ( sem ) {
		sem_getvalue(sem->sem, &ret);
		if ( ret < 0 ) {
			ret = 0;
		}
	}
	return (Uint32)ret;
}

int SDL_SemPost(SDL_sem *sem)
{
	int retval;

	if ( ! sem ) {
		SDL_SetError("Passed a NULL semaphore");
		return -1;
	}

	retval = sem_post(sem->sem);
	if ( retval < 0 ) {
		SDL_SetError("sem_post() failed");
	}
	return retval;
}

/* 
 * BEGIN inlined uthread_sem.c.  This is done here so that no extra libraries
 * or include files not present in BSD/OS are required
*/

/*
 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice(s), this list of conditions and the following disclaimer as
 *    the first lines of this file unmodified other than the possible
 *    addition of one or more copyright notices.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice(s), this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD: src/lib/libc_r/uthread/uthread_sem.c,v 1.3.2.1 2000/07/18 02:05:57 jasone Exp $
 */

#include <errno.h>
#include <pthread.h>

/* Begin thread_private.h kluge */
/*
 * These come out of (or should go into) thread_private.h - rather than have 
 * to copy (or symlink) the files from the source tree these definitions are 
 * inlined here.  Obviously these go away when this module is part of libc.
*/
struct sem {
#define SEM_MAGIC       ((u_int32_t) 0x09fa4012)
        u_int32_t       magic;
        pthread_mutex_t lock;
        pthread_cond_t  gtzero;
        u_int32_t       count;
        u_int32_t       nwaiters;
};

extern pthread_once_t _thread_init_once;
extern int _threads_initialized;
extern void  _thread_init __P((void));
#define THREAD_INIT() \
	(void) pthread_once(&_thread_init_once, _thread_init)
#define THREAD_SAFE() \
	(_threads_initialized != 0)

#define _SEM_CHECK_VALIDITY(sem)		\
	if ((*(sem))->magic != SEM_MAGIC) {	\
		errno = EINVAL;			\
		retval = -1;			\
		goto RETURN;			\
	}
/* End thread_private.h kluge */

int
sem_init(sem_t *sem, int pshared, unsigned int value)
{
	int	retval;

	if (!THREAD_SAFE())
		THREAD_INIT();

	/*
	 * Range check the arguments.
	 */
	if (pshared != 0) {
		/*
		 * The user wants a semaphore that can be shared among
		 * processes, which this implementation can't do.  Sounds like a
		 * permissions problem to me (yeah right).
		 */
		errno = EPERM;
		retval = -1;
		goto RETURN;
	}

	if (value > SEM_VALUE_MAX) {
		errno = EINVAL;
		retval = -1;
		goto RETURN;
	}

	*sem = (sem_t)malloc(sizeof(struct sem));
	if (*sem == NULL) {
		errno = ENOSPC;
		retval = -1;
		goto RETURN;
	}

	/*
	 * Initialize the semaphore.
	 */
	if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
		free(*sem);
		errno = ENOSPC;
		retval = -1;
		goto RETURN;
	}

	if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
		pthread_mutex_destroy(&(*sem)->lock);
		free(*sem);
		errno = ENOSPC;
		retval = -1;
		goto RETURN;
	}
	
	(*sem)->count = (u_int32_t)value;
	(*sem)->nwaiters = 0;
	(*sem)->magic = SEM_MAGIC;

	retval = 0;
  RETURN:
	return retval;
}

int
sem_destroy(sem_t *sem)
{
	int	retval;
	
	_SEM_CHECK_VALIDITY(sem);

	/* Make sure there are no waiters. */
	pthread_mutex_lock(&(*sem)->lock);
	if ((*sem)->nwaiters > 0) {
		pthread_mutex_unlock(&(*sem)->lock);
		errno = EBUSY;
		retval = -1;
		goto RETURN;
	}
	pthread_mutex_unlock(&(*sem)->lock);
	
	pthread_mutex_destroy(&(*sem)->lock);
	pthread_cond_destroy(&(*sem)->gtzero);
	(*sem)->magic = 0;

	free(*sem);

	retval = 0;
  RETURN:
	return retval;
}

sem_t *
sem_open(const char *name, int oflag, ...)
{
	errno = ENOSYS;
	return SEM_FAILED;
}

int
sem_close(sem_t *sem)
{
	errno = ENOSYS;
	return -1;
}

int
sem_unlink(const char *name)
{
	errno = ENOSYS;
	return -1;
}

int
sem_wait(sem_t *sem)
{
	int	retval;

	pthread_testcancel();
	
	_SEM_CHECK_VALIDITY(sem);

	pthread_mutex_lock(&(*sem)->lock);

	while ((*sem)->count == 0) {
		(*sem)->nwaiters++;
		pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
		(*sem)->nwaiters--;
	}
	(*sem)->count--;

	pthread_mutex_unlock(&(*sem)->lock);

	retval = 0;
  RETURN:

	pthread_testcancel();
	return retval;
}

int
sem_trywait(sem_t *sem)
{
	int	retval;

	_SEM_CHECK_VALIDITY(sem);

	pthread_mutex_lock(&(*sem)->lock);

	if ((*sem)->count > 0) {
		(*sem)->count--;
		retval = 0;
	} else {
		errno = EAGAIN;
		retval = -1;
	}
	
	pthread_mutex_unlock(&(*sem)->lock);

  RETURN:
	return retval;
}

int
sem_post(sem_t *sem)
{
	int	retval;

	_SEM_CHECK_VALIDITY(sem);

	pthread_mutex_lock(&(*sem)->lock);

	(*sem)->count++;
	if ((*sem)->nwaiters > 0) {
		/*
		 * We must use pthread_cond_broadcast() rather than
		 * pthread_cond_signal() in order to assure that the highest
		 * priority thread is run by the scheduler, since
		 * pthread_cond_signal() signals waiting threads in FIFO order.
		 */
		pthread_cond_broadcast(&(*sem)->gtzero);
	}

	pthread_mutex_unlock(&(*sem)->lock);

	retval = 0;
  RETURN:
	return retval;
}

int
sem_getvalue(sem_t *sem, int *sval)
{
	int	retval;

	_SEM_CHECK_VALIDITY(sem);

	pthread_mutex_lock(&(*sem)->lock);
	*sval = (int)(*sem)->count;
	pthread_mutex_unlock(&(*sem)->lock);

	retval = 0;
  RETURN:
	return retval;
}

/* END of inlined uthread_sem.c */
#endif /* SDL_USE_PTHREADS */