Added Greg Ercolanos filedescripter support

Fixed Text Width bug.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@2325 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2002-06-27 23:18:12 +00:00
parent cdc15f49a6
commit a4e0a9adb5
4 changed files with 273 additions and 45 deletions

View File

@ -1,5 +1,7 @@
CHANGES IN FLTK 1.1.0
- Added Greg Ercolano's MacOS filedescriptor support.
- Fixed text width bug.
- A change in fl_fix_focus() broken click-focus in FLWM.
- Cygwin with -mnocygwin didn't like the FL/math.h
header file.

View File

@ -87,14 +87,12 @@ KNOWN MacFLTK BUGS
The following FLTK things are not implemented or don't work
at present:
- File handles (Fl::add_fd) are not implemented.
- Line styles are not fully implemented.
- Sub-sub-subwindow not tested.
- Image transparency is implemented as "screen-door" only
- The 'shiny' demo needs work (flush/aglFlush).
- Threads are not implemented.
- OpenGL subwindow during window resize changes position
- fl_measure returns wrong width (wrong current font?)
TEST SUITE STATUS

View File

@ -1,5 +1,5 @@
//
// "$Id: Fl_mac.cxx,v 1.1.2.27 2002/06/27 04:29:39 matthiaswm Exp $"
// "$Id: Fl_mac.cxx,v 1.1.2.28 2002/06/27 23:18:12 matthiaswm Exp $"
//
// MacOS specific code for the Fast Light Tool Kit (FLTK).
//
@ -51,6 +51,17 @@
#include <stdlib.h>
#include "flstring.h"
#include <unistd.h>
#include <pthread.h>
// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING
#ifdef DEBUG_SELECT
#include <stdio.h> // testing
#define DEBUGMSG(msg) fprintf(stderr, msg);
#define DEBUGPERRORMSG(msg) perror(msg)
#else
#define DEBUGMSG(msg)
#define DEBUGPERRORMSG(msg)
#endif /*DEBUGSELECT*/
// external functions
extern Fl_Window* fl_find(Window);
@ -89,7 +100,7 @@ extern Fl_Window* fl_xmousewin;
#endif
enum { kEventClassFLTK = 'fltk' };
enum { kEventFLTKBreakLoop = 1 };
enum { kEventFLTKBreakLoop = 1, kEventFLTKDataReady };
/**
* Mac keyboard lookup table
@ -128,56 +139,166 @@ void (*fl_lock_function)() = nothing;
void (*fl_unlock_function)() = nothing;
/**
* \todo This funtion is not yet implemented!
*/
void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v )
//
// Select interface
//
#define POLLIN 1
#define POLLOUT 4
#define POLLERR 8
struct FD
{
#pragma unused ( n )
#pragma unused ( events )
#pragma unused ( cb )
#pragma unused ( v )
int fd;
short events;
void (*cb)(int, void*);
void* arg;
};
static int nfds = 0;
static int fd_array_size = 0;
static FD *fd = 0;
static int G_pipe[2] = { 0,0 }; // work around pthread_cancel() problem
enum GetSet { GET = 1, SET = 2 };
static pthread_mutex_t select_mutex; // global data lock
// MAXFD ACCESSOR (HANDLES LOCKING)
static void MaxFD(GetSet which, int& val)
{
static int maxfd = 0;
pthread_mutex_lock(&select_mutex);
if ( which == GET ) { val = maxfd; }
else { maxfd = val; }
pthread_mutex_unlock(&select_mutex);
}
/**
* \todo This funtion is not yet implemented!
*/
void Fl::add_fd(int fd, void (*cb)(int, void*), void* v)
// FDSET ACCESSOR (HANDLES LOCKING)
static void Fdset(GetSet which, fd_set& r, fd_set &w, fd_set &x)
{
#pragma unused ( fd )
#pragma unused ( cb )
#pragma unused ( v )
static fd_set fdsets[3];
pthread_mutex_lock(&select_mutex);
if ( which == GET ) { r = fdsets[0]; w = fdsets[1]; x = fdsets[2]; }
else { fdsets[0] = r; fdsets[1] = w; fdsets[2] = x; }
pthread_mutex_unlock(&select_mutex);
}
/**
* \todo This funtion is not yet implemented!
*/
void Fl::remove_fd(int n, int events)
void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v )
{
#pragma unused ( n )
#pragma unused ( events )
remove_fd(n, events);
int i = nfds++;
if (i >= fd_array_size) {
FD *temp;
fd_array_size = 2*fd_array_size+1;
if (!fd) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); }
else { temp = (FD*)realloc(fd, fd_array_size*sizeof(FD)); }
if (!temp) return;
fd = temp;
}
fd[i].cb = cb;
fd[i].arg = v;
fd[i].fd = n;
fd[i].events = events;
{
int maxfd;
fd_set r, w, x;
MaxFD(GET, maxfd);
Fdset(GET, r, w, x);
if (events & POLLIN) FD_SET(n, &r);
if (events & POLLOUT) FD_SET(n, &w);
if (events & POLLERR) FD_SET(n, &x);
if (n > maxfd) maxfd = n;
Fdset(SET, r, w, x);
MaxFD(SET, maxfd);
}
}
void Fl::add_fd(int fd, void (*cb)(int, void*), void* v)
{
Fl::add_fd(fd, POLLIN, cb, v);
}
/**
* \todo This funtion is not yet implemented!
*/
void Fl::remove_fd(int n)
void Fl::remove_fd(int n, int events)
{
int i,j;
for (i=j=0; i<nfds; i++) {
if (fd[i].fd == n) {
int e = fd[i].events & ~events;
if (!e) continue; // if no events left, delete this fd
fd[i].events = e;
}
// move it down in the array if necessary:
if (j<i)
{ fd[j] = fd[i]; }
j++;
}
nfds = j;
{
int maxfd;
fd_set r, w, x;
MaxFD(GET, maxfd);
Fdset(GET, r, w, x);
if (events & POLLIN) FD_CLR(n, &r);
if (events & POLLOUT) FD_CLR(n, &w);
if (events & POLLERR) FD_CLR(n, &x);
if (n == maxfd) maxfd--;
Fdset(SET, r, w, x);
MaxFD(SET, maxfd);
}
}
void Fl::remove_fd(int n)
{
remove_fd(n, -1);
}
/**
* \todo check if there is actually a message pending!
*/
int fl_ready()
int fl_ready()
{
return 1;
}
// CHECK IF USER DATA READY
static int CheckDataReady(fd_set& r, fd_set& w, fd_set& x)
{
int maxfd;
MaxFD(GET, maxfd);
timeval t = { 0, 1 }; // quick check
int ret = ::select(maxfd+1, &r, &w, &x, &t);
if ( ret == -1 )
{ DEBUGPERRORMSG("CheckDataReady(): select()"); }
return(ret);
}
// HANDLE DATA READY CALLBACKS
static void HandleDataReady(fd_set& r, fd_set& w, fd_set& x)
{
for (int i=0; i<nfds; i++)
{
// fprintf(stderr, "CHECKING FD %d OF %d (%d)\n", i, nfds, fd[i].fd);
int f = fd[i].fd;
short revents = 0;
if (FD_ISSET(f, &r)) revents |= POLLIN;
if (FD_ISSET(f, &w)) revents |= POLLOUT;
if (FD_ISSET(f, &x)) revents |= POLLERR;
if (fd[i].events & revents)
{
DEBUGMSG("DOING CALLBACK: ");
fd[i].cb(f, fd[i].arg);
DEBUGMSG("DONE\n");
}
}
}
/**
* We can make every event pass through this function
@ -214,6 +335,30 @@ static pascal OSStatus carbonDispatchHandler( EventHandlerCallRef nextHandler, E
case kEventFLTKBreakLoop:
ret = noErr;
break;
case kEventFLTKDataReady:
{
DEBUGMSG("DATA READY EVENT: RECEIVED\n");
// CHILD THREAD TELLS US DATA READY
// Check to see what's ready, and invoke user's cb's
//
fd_set r, w, x;
Fdset(GET, r, w, x);
switch ( CheckDataReady(r, w, x) )
{
case 0: // NO DATA
break;
case -1: // ERROR
break;
default: // DATA READY
HandleDataReady(r, w, x);
break;
}
}
ret = noErr;
break;
}
}
if ( ret == eventNotHandledErr )
@ -239,6 +384,54 @@ static void timerProcCB( EventLoopTimerRef, void* )
}
// DATA READY THREAD
// Separate thread, watches for changes in user's file descriptors.
// Sends a 'data ready event' to the main thread if any change.
//
static void *dataready_thread(void *userdata)
{
EventRef drEvent;
CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady,
0, kEventAttributeUserEvent, &drEvent);
EventQueueRef eventqueue = (EventQueueRef)userdata;
// Thread safe local copy
int maxfd;
fd_set r, w, x;
MaxFD(GET, maxfd);
Fdset(GET, r, w, x);
// TACK ON FD'S FOR 'CANCEL PIPE'
FD_SET(G_pipe[0], &r);
if ( G_pipe[0] > maxfd ) maxfd = G_pipe[0];
// FOREVER UNTIL THREAD CANCEL OR ERROR
while ( 1 )
{
timeval t = { 1000, 0 }; // 1000 seconds;
int ret = ::select(maxfd+1, &r, &w, &x, &t);
pthread_testcancel(); // OSX 10.0.4 and under: need to do this
// so parent can cancel us :(
switch ( ret )
{
case 0: // NO DATA
continue;
case -1: // ERROR
{
DEBUGPERRORMSG("CHILD THREAD: select() failed");
return(NULL); // error? exit thread
}
default: // DATA READY
{
DEBUGMSG("DATA READY EVENT: SENDING\n");
PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard );
return(NULL); // done with thread
}
}
}
}
/**
* break the current event loop
*/
@ -298,19 +491,48 @@ static double do_queued_events( double time = 0.0 )
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseWheelMoved },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassFLTK, kEventFLTKBreakLoop } };
ret = InstallEventHandler( target, dispatchHandler, 15, dispatchEvents, 0, 0L );
{ kEventClassFLTK, kEventFLTKBreakLoop },
{ kEventClassFLTK, kEventFLTKDataReady } };
ret = InstallEventHandler( target, dispatchHandler, 16, dispatchEvents, 0, 0L );
ret = InstallEventLoopTimer( GetMainEventLoop(), 0, 0, NewEventLoopTimerUPP( timerProcCB ), 0, &timer );
}
got_events = 0;
// START A THREAD TO WATCH FOR DATA READY
static pthread_t dataready_tid = 0;
if ( nfds )
{
void *userdata = (void*)GetCurrentEventQueue();
// PREPARE INTER-THREAD DATA
pthread_mutex_init(&select_mutex, NULL);
if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; }
if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; }
pipe(G_pipe);
DEBUGMSG("*** START THREAD\n");
pthread_create(&dataready_tid, NULL, dataready_thread, userdata);
}
fl_unlock_function();
if ( time > 0.0 )
{
SetEventLoopTimerNextFireTime( timer, time );
RunApplicationEventLoop(); // will return after the previously set time
RunApplicationEventLoop(); // wil return after the previously set time
if ( dataready_tid != 0 )
{
DEBUGMSG("*** CANCEL THREAD: ");
pthread_cancel(dataready_tid); // cancel first
write(G_pipe[1], "x", 1); // then wakeup thread from select
pthread_join(dataready_tid, NULL); // wait for thread to finish
if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; }
if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; }
dataready_tid = 0;
DEBUGMSG("OK\n");
}
}
else
{
@ -319,6 +541,17 @@ static double do_queued_events( double time = 0.0 )
PostEventToQueue( GetCurrentEventQueue(), breakEvent, kEventPriorityStandard );
RunApplicationEventLoop();
ReleaseEvent( breakEvent );
if ( dataready_tid != 0 )
{
DEBUGMSG("*** CANCEL THREAD: ");
pthread_cancel(dataready_tid); // cancel first
write(G_pipe[1], "x", 1); // then wakeup thread from select
pthread_join(dataready_tid, NULL); // wait for thread to finish
if ( G_pipe[0] ) { close(G_pipe[0]); G_pipe[0] = 0; }
if ( G_pipe[1] ) { close(G_pipe[1]); G_pipe[1] = 0; }
dataready_tid = 0;
DEBUGMSG("OK\n");
}
}
fl_lock_function();
@ -1450,6 +1683,6 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
//
// End of "$Id: Fl_mac.cxx,v 1.1.2.27 2002/06/27 04:29:39 matthiaswm Exp $".
// End of "$Id: Fl_mac.cxx,v 1.1.2.28 2002/06/27 23:18:12 matthiaswm Exp $".
//

View File

@ -1,5 +1,5 @@
//
// "$Id: fl_font_mac.cxx,v 1.1.2.9 2002/06/27 04:29:39 matthiaswm Exp $"
// "$Id: fl_font_mac.cxx,v 1.1.2.10 2002/06/27 23:18:12 matthiaswm Exp $"
//
// MacOS font selection routines for the Fast Light Tool Kit (FLTK).
//
@ -27,6 +27,7 @@
//: TextSize, TextFont
//: GetFNum (theName: Str255; VAR familyID: Integer);
//: FUNCTION FMSwapFont (inRec: FMInput): FMOutPtr;
//: SetFractEnable
Fl_FontSize::Fl_FontSize(const char* name, int Size) {
knowMetrics = 0;
@ -126,13 +127,7 @@ static Fl_FontSize* find(int fnum, int size) {
////////////////////////////////////////////////////////////////
// Public interface:
int fl_font_ = 0;
int fl_size_ = 0;
void fl_font(int fnum, int size) {
if (fnum == fl_font_ && size == fl_size_) return;
fl_font_ = fnum;
fl_size_ = size;
fl_font(find(fnum, size));
}
@ -159,5 +154,5 @@ void fl_draw(const char* str, int n, int x, int y) {
}
//
// End of "$Id: fl_font_mac.cxx,v 1.1.2.9 2002/06/27 04:29:39 matthiaswm Exp $".
// End of "$Id: fl_font_mac.cxx,v 1.1.2.10 2002/06/27 23:18:12 matthiaswm Exp $".
//