[BeOS] Take in account mayWait parameter in nsAppShell::ProcessNextNativeEvent(). Bug 343100. p=sergei_d, r=thesuckiestemail, BeOS-only

This commit is contained in:
sergei_d%fi.tartu.ee 2006-06-30 22:25:31 +00:00
Родитель 4ed461404d
Коммит 2a761195c7
2 изменённых файлов: 74 добавлений и 125 удалений

Просмотреть файл

@ -42,40 +42,20 @@
#include "nsAppShell.h"
#include "nsSwitchToUIThread.h"
#include "prprf.h"
#include <Application.h>
#include <stdlib.h>
static sem_id my_find_sem(const char *name)
{
sem_id ret = B_ERROR;
/* Get the sem_info for every sempahore in this team. */
sem_info info;
int32 cookie = 0;
while(get_next_sem_info(0, &cookie, &info) == B_OK)
{
if(strcmp(name, info.name) == 0)
{
ret = info.sem;
break;
}
}
return ret;
}
//-------------------------------------------------------------------------
//
// nsAppShell constructor
//
//-------------------------------------------------------------------------
nsAppShell::nsAppShell()
: is_port_error(false)
: is_port_error(false), scheduled (false)
{
eventport = nsnull;
eventport = -1; // 0 is legal value for port_id!
}
@ -90,42 +70,21 @@ NS_IMETHODIMP nsAppShell::Init()
// system wide unique names
// NOTE: this needs to be run from within the main application thread
char portname[64];
char semname[64];
char portname[B_OS_NAME_LENGTH];
PR_snprintf(portname, sizeof(portname), "event%lx", (long unsigned) PR_GetCurrentThread());
PR_snprintf(semname, sizeof(semname), "sync%lx", (long unsigned) PR_GetCurrentThread());
#ifdef DEBUG
printf("nsAppShell::Create portname: %s, semname: %s\n", portname, semname);
printf("nsAppShell::Create portname: %s\n", portname);
#endif
/*
* Set up the port for communicating. As restarts thru execv may occur
* and ports survive those (with faulty events as result). We need to take extra
* care that the port is created for this launch, otherwise we need to reopen it
* so that faulty messages gets lost.
*
* We do this by checking if the sem has been created. If it is we can reuse the port (if it exists).
* Otherwise we need to create the sem and the port, deleting any open ports before.
* TODO: The semaphore is no longer needed for syncing, so it's only use is for detecting if the
* port needs to be reopened. This should be replaced, but I'm not sure how -tqh
*/
syncsem = my_find_sem(semname);
eventport = find_port(portname);
if (B_ERROR != syncsem)
{
if (eventport < 0)
{
eventport = create_port(200, portname);
}
return nsBaseAppShell::Init();
}
if (eventport >= 0)
// Clean up things. Restart process in toolkit may leave old port alive.
if ((eventport = find_port(portname)) >= 0)
{
close_port(eventport);
delete_port(eventport);
}
eventport = create_port(200, portname);
syncsem = create_sem(0, semname);
return nsBaseAppShell::Init();
}
@ -140,107 +99,97 @@ nsAppShell::~nsAppShell()
{
close_port(eventport);
delete_port(eventport);
delete_sem(syncsem);
if (be_app->Lock())
{
be_app->Quit();
}
}
// This version ignores mayWait flag totally
PRBool nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
{
bool gotMessage = false;
// should we check for eventport initialization ?
if (eventport == 0)
if (eventport < 0)
{
char portname[64];
char portname[B_OS_NAME_LENGTH];
PR_snprintf(portname, sizeof(portname), "event%lx", (long unsigned) PR_GetCurrentThread());
// XXX - Do we really need to search eventport every time? There is one istance of AppShell per app
// and finding it once in Init() might be sufficient.
// At least version this version with if(!eventport) worked for me well in tests.
// It may add some performance, sprintf with format is bit expensive for huge message flood.
if((eventport = find_port(portname)) < 0)
{
// not initialized
// not initialized
#ifdef DEBUG
printf("nsAppShell::DispatchNativeEvent() was called before init\n");
#endif
return gotMessage;
}
}
// Previously we collected events in RetrieveAllEvents via simple read_port,
// and unblocking was performed by sending fake 'natv' message from _pl_NativeNotify()
// Currently we ignoring event type, previously we had 5 priority levels, different for mouse, kbd etc.
// MS Windows code sets some priority for kbd and IME events by ignoring mayWait
// There is huge need now to rewrite MouseMove handling in nsWindow.cpp.
// mayWait here blocked app totally until I replaced read_port with read_port_etc.
// I suspect it may be related to non-implemented ScheduleNativeEventCallback()
if (port_count(eventport) || mayWait)
if (port_count(eventport))
gotMessage = InvokeBeOSMessage(0);
// There is next message in port queue
if (port_count(eventport) && !mayWait)
{
#ifdef DEBUG
printf("PNNE\n");
#endif
EventItem *newitem = new EventItem;
if (!newitem)
return gotMessage;
newitem->code = 0;
newitem->ifdata.data = nsnull;
newitem->ifdata.waitingThread = 0;
// Here is interesting thing, according to logic described in
// https://bugzilla.mozilla.org/show_bug.cgi?id=337550#c17
// read_port() is what should be here, if we take mayWait in account,
// but application even don't start with that. Or, if it does, blocks in first window created.
// Using read_port_etc with real timeout allows it work as expected.
// Second interesting fact, if we don't use || mayWait condition, CPU load depends on timeout value -
// smaller value, bigger CPU load.
if (read_port_etc(eventport, &newitem->code, &newitem->ifdata, sizeof(newitem->ifdata), B_TIMEOUT, 100000) < 0)
if (!scheduled)
{
delete newitem;
newitem = nsnull;
is_port_error = true;
return gotMessage;
// There is new (not scheduled) event and we cannot wait.
// So inform AppShell about existence of new event.
// Actually it should be called from something like BLooper::MessageReceived(),
// or, in our case, in nsToolkit CallMethod*()
NativeEventCallback();
}
else
{
scheduled = false;
gotMessage = InvokeBeOSMessage(0);
}
gotMessage = true;
InvokeBeOSMessage(newitem);
delete newitem;
newitem = nsnull;
#ifdef DEBUG
printf("Retrived ni = %p\n", newitem);
#endif
}
// Hack. Emulating logic for mayWait.
// Allow next event to pass through (if it appears inside 100000 uS)
// Actually it should block and then be unblocked from independent thread
// In that case read_port() should be used.
if (mayWait)
gotMessage = InvokeBeOSMessage(100000);
return gotMessage;
}
//-------------------------------------------------------------------------
void nsAppShell::ScheduleNativeEventCallback()
{
#ifdef DEBUG
printf("SNEC\n");
#endif
// ??? what to do here? Invoke fake message like that 'natv' from gone plevent ?
if (eventport < 0)
return;
// This should be done from different thread in reality in order to unblock
ThreadInterfaceData id;
id.data = 0;
id.waitingThread = find_thread(NULL);
write_port(eventport, 'natv', &id, sizeof(id));
scheduled = true;
}
void nsAppShell::InvokeBeOSMessage(EventItem *item)
bool nsAppShell::InvokeBeOSMessage(bigtime_t timeout)
{
int32 code;
ThreadInterfaceData id;
id.data = 0;
id.waitingThread = 0;
code = item->code;
id = item->ifdata;
MethodInfo *mInfo = (MethodInfo *)id.data;
int32 code;
ThreadInterfaceData id;
if (read_port_etc(eventport, &code, &id, sizeof(id), B_TIMEOUT, timeout) < 0)
{
is_port_error = true;
return false;
}
id.waitingThread = 0;
MethodInfo *mInfo = (MethodInfo *)id.data;
if (code != 'natv')
mInfo->Invoke();
if (id.waitingThread != 0)
{
resume_thread(id.waitingThread);
}
delete mInfo;
if (id.waitingThread != 0)
resume_thread(id.waitingThread);
delete mInfo;
return true;
}

Просмотреть файл

@ -44,14 +44,14 @@
struct ThreadInterfaceData
{
void *data;
thread_id waitingThread;
void* data;
thread_id waitingThread;
};
struct EventItem
{
int32 code;
ThreadInterfaceData ifdata;
int32 code;
ThreadInterfaceData ifdata;
};
struct MethodInfo;
@ -64,17 +64,17 @@ class nsAppShell : public nsBaseAppShell
{
public:
nsAppShell();
nsresult Init();
nsresult Init();
protected:
virtual void ScheduleNativeEventCallback();
virtual PRBool ProcessNextNativeEvent(PRBool mayWait);
virtual ~nsAppShell();
virtual void ScheduleNativeEventCallback();
virtual PRBool ProcessNextNativeEvent(PRBool mayWait);
virtual ~nsAppShell();
private:
port_id eventport;
sem_id syncsem;
bool is_port_error;
void InvokeBeOSMessage(EventItem *item);
port_id eventport;
volatile bool scheduled;
bool is_port_error;
bool InvokeBeOSMessage(bigtime_t timeout);
};
#endif // nsAppShell_h__