MGR: Multiple fixes to Async GUI RPCs, message polling, task bar tooltip updates

svn path=/trunk/boinc/; revision=16196
This commit is contained in:
Charlie Fenton 2008-10-14 03:28:34 +00:00
parent bc35ee14cf
commit 655301bfda
10 changed files with 127 additions and 53 deletions

View File

@ -8311,3 +8311,24 @@ David 12 Oct 2008
html/user/
create_profile.php
Charlie 13 Oct 2008
- MGR: Multiple fixes to Async GUI RPCs:
- Reject most events during RPC Wait dialog. This should
eliminate most asserts due to undesired recursion in
CMainDocument::RequestRPC().
- Always update message list every second, even when in other
view tabs or when manager is minimized.
- Eliminate separate task bar update timer, update with other
periodic RPCs.
- Always update task information in task bar icon tooltip when
user hovers mouse over task bar icon.
- Improve enabling / disabling of task bar icon menu items.
clientgui/
AsyncRPC.cpp,.h
BOINCGUIApp.cpp,.h
BOINCTaskBar.cpp,.h
Events.h
MainDocument.cpp,.h

View File

@ -451,15 +451,17 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) {
// a dialog allowing the user to cancel.
if (request.rpcType == RPC_TYPE_WAIT_FOR_COMPLETION) {
// TODO: proper handling if a second user request is received while first is pending ??
// CBOINCGUIApp::FilterEvent() blocks eventrs during our "Please
// Wait" dialog, which could cause undesirable recursion here
if (m_bWaitingForRPC) {
wxLogMessage(wxT("Second user RPC request while another was pending"));
//wxASSERT(false);
wxASSERT(false);
return -1;
}
m_bWaitingForRPC = true;
// Don't show dialog if RPC completes before RPC_WAIT_DLG_DELAY
wxStopWatch Dlgdelay = wxStopWatch();
m_RPCWaitDlg = new AsyncRPCDlg();
m_bWaitingForRPC = true;
do {
// Simulate handling of CRPCFinishedEvent but don't allow any other events (so no user activity)
// Allow RPC thread to run while we wait for it
@ -514,6 +516,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) {
RPC_requests.clear();
current_rpc_request.clear();
m_bNeedRefresh = false;
m_bNeedTaskBarRefresh = false;
// We will be reconnected to the same client (if possible) by
// CBOINCDialUpManager::OnPoll() and CNetworkConnection::Poll().
@ -594,15 +597,21 @@ void CMainDocument::HandleCompletedRPC() {
*(current_rpc_request.resultPtr) = retval;
}
if (current_rpc_request.rpcType == RPC_TYPE_ASYNC_WITH_REFRESH_AFTER) {
if (!retval) {
m_bNeedRefresh = true;
}
}
// Post-processing
if (! retval) {
switch (current_rpc_request.which_rpc) {
if (current_rpc_request.rpcType == RPC_TYPE_ASYNC_WITH_REFRESH_AFTER) {
if (!retval) {
m_bNeedRefresh = true;
}
}
if (current_rpc_request.rpcType == RPC_TYPE_ASYNC_WITH_UPDATE_TASKBAR_ICON_AFTER) {
if (!retval) {
m_bNeedTaskBarRefresh = true;
}
}
switch (current_rpc_request.which_rpc) {
case RPC_GET_STATE:
if (current_rpc_request.exchangeBuf && !retval) {
CC_STATE* arg1 = (CC_STATE*)current_rpc_request.arg1;
@ -742,6 +751,21 @@ void CMainDocument::HandleCompletedRPC() {
}
}
if (m_bNeedTaskBarRefresh && !m_bWaitingForRPC) {
m_bNeedTaskBarRefresh = false;
CTaskBarIcon* pTaskbar = wxGetApp().GetTaskBarIcon();
if (pTaskbar) {
CTaskbarEvent event(wxEVT_TASKBAR_REFRESH, pTaskbar);
pTaskbar->ProcessEvent(event);
}
}
// CachedMessageUpdate() does not do any RPCs, so it is safe here
if (current_rpc_request.rpcType == RPC_TYPE_ASYNC_WITH_UPDATE_MESSAGE_LIST_AFTER) {
CachedMessageUpdate();
}
current_rpc_request.clear();
// Start the next RPC request.

View File

@ -90,9 +90,15 @@ enum ASYNC_RPC_TYPE {
// Periodic RPC: post request on queue and return immediately
// (requested due to a timer interrupt.)
RPC_TYPE_ASYNC_NO_REFRESH,
// Periodic RPCas above, but on completion also process a
// Periodic RPC as above, but on completion also process a
// wxEVT_FRAME_REFRESHVIEW event to refresh the display.
RPC_TYPE_ASYNC_WITH_REFRESH_AFTER,
// Periodic RPC as above, but on completion also update message
// list by calling CMainDocument::CachedMessageUpdate().
RPC_TYPE_ASYNC_WITH_UPDATE_MESSAGE_LIST_AFTER,
// Periodic RPC as above, but on completion also process a
// wxEVT_TASKBAR_REFRESH event to refresh the taskbar icon.
RPC_TYPE_ASYNC_WITH_UPDATE_TASKBAR_ICON_AFTER,
NUM_RPC_TYPES
};

View File

@ -865,8 +865,34 @@ bool CBOINCGUIApp::IsModalDialogDisplayed() {
if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) {
return true;
}
if (m_pDocument) {
if (m_pDocument->WaitingForRPC()) {
return true;
}
}
return false;
}
// Prevent recursive entry of CMainDocument::RequestRPC()
int CBOINCGUIApp::FilterEvent(wxEvent &event) {
if (!m_pDocument) return -1;
if (!m_pDocument->WaitingForRPC()) return -1;
// If in RPC Please Wait dialog, reject all events except
// RPC Finished or those for that dialog or its children.
if (event.GetEventType() == wxEVT_RPC_FINISHED) return -1;
wxDialog* theRPCWaitDialog = m_pDocument->GetRPCWaitDialog();
wxObject * theObject = event.GetEventObject();
while (theObject) {
if (! theObject->IsKindOf(CLASSINFO(wxWindow))) break;
if (theObject == theRPCWaitDialog) return -1;
theObject = ((wxWindow*)theObject)->GetParent();
}
return false;
}
const char *BOINC_RCSID_487cbf3018 = "$Id$";

View File

@ -157,6 +157,7 @@ public:
int x = wxDefaultCoord, int y = wxDefaultCoord);
bool IsModalDialogDisplayed();
int FilterEvent(wxEvent &event);
DECLARE_EVENT_TABLE()
};

View File

@ -41,12 +41,12 @@
DEFINE_EVENT_TYPE(wxEVT_TASKBAR_RELOADSKIN)
DEFINE_EVENT_TYPE(wxEVT_TASKBAR_REFRESH)
BEGIN_EVENT_TABLE(CTaskBarIcon, wxTaskBarIconEx)
EVT_IDLE(CTaskBarIcon::OnIdle)
EVT_CLOSE(CTaskBarIcon::OnClose)
EVT_TIMER(ID_TB_TIMER, CTaskBarIcon::OnRefresh)
EVT_TASKBAR_REFRESH(CTaskBarIcon::OnRefresh)
EVT_TASKBAR_RELOADSKIN(CTaskBarIcon::OnReloadSkin)
EVT_TASKBAR_LEFT_DCLICK(CTaskBarIcon::OnLButtonDClick)
EVT_MENU(wxID_OPEN, CTaskBarIcon::OnOpen)
@ -88,19 +88,11 @@ CTaskBarIcon::CTaskBarIcon(wxString title, wxIcon* icon, wxIcon* iconDisconnecte
m_dtLastHoverDetected = wxDateTime((time_t)0);
m_bMouseButtonPressed = false;
m_pRefreshTimer = new wxTimer(this, ID_TB_TIMER);
m_pRefreshTimer->Start(1000); // Send event every second
}
CTaskBarIcon::~CTaskBarIcon() {
RemoveIcon();
if (m_pRefreshTimer) {
m_pRefreshTimer->Stop();
delete m_pRefreshTimer;
}
}
@ -128,7 +120,7 @@ void CTaskBarIcon::OnClose(wxCloseEvent& event) {
}
void CTaskBarIcon::OnRefresh(wxTimerEvent& WXUNUSED(event)) {
void CTaskBarIcon::OnRefresh(CTaskbarEvent& WXUNUSED(event)) {
wxLogTrace(wxT("Function Start/End"), wxT("CTaskBarIcon::OnRefresh - Function Begin"));
CMainDocument* pDoc = wxGetApp().GetDocument();
@ -643,7 +635,7 @@ void CTaskBarIcon::AdjustMenuItems(wxMenu* pMenu) {
for (loc = 0; loc < pMenu->GetMenuItemCount(); loc++) {
pMenuItem = pMenu->FindItemByPosition(loc);
if (is_dialog_detected) {
if (is_dialog_detected && (pMenuItem->GetId() != wxID_OPEN)) {
pMenuItem->Enable(false);
} else {
pMenuItem->Enable(!(pMenuItem->IsSeparator()));
@ -680,11 +672,15 @@ void CTaskBarIcon::AdjustMenuItems(wxMenu* pMenu) {
pMenu->Enable(ID_TB_SUSPEND, false);
} else {
pMenu->Check(ID_TB_SUSPEND, true);
if (!is_dialog_detected) {
pMenu->Enable(ID_TB_SUSPEND, true);
}
}
} else {
pMenu->Check(ID_TB_SUSPEND, false);
if (!is_dialog_detected) {
pMenu->Enable(ID_TB_SUSPEND, true);
}
}
}

View File

@ -46,7 +46,7 @@ public:
void OnIdle(wxIdleEvent& event);
void OnClose(wxCloseEvent& event);
void OnRefresh(wxTimerEvent& event);
void OnRefresh(CTaskbarEvent& event);
void OnReloadSkin(CTaskbarEvent& event);
void OnMouseMove(wxTaskBarIconEvent& event);
@ -80,8 +80,6 @@ public:
private:
wxDateTime m_dtLastHoverDetected;
wxTimer* m_pRefreshTimer;
bool m_bMouseButtonPressed;
void ResetTaskBar();
@ -116,9 +114,11 @@ public:
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( wxEVT_TASKBAR_RELOADSKIN, 10100 )
DECLARE_EVENT_TYPE( wxEVT_TASKBAR_REFRESH, 10101 )
END_DECLARE_EVENT_TYPES()
#define EVT_TASKBAR_RELOADSKIN(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_TASKBAR_RELOADSKIN, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL),
#define EVT_TASKBAR_REFRESH(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_TASKBAR_REFRESH, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL),
#endif

View File

@ -65,7 +65,6 @@
#define ID_SIMPLE_PREFERENCES 6606
#define ID_SIMPLE_MESSAGESVIEW 6607
#define ID_SIMPLE_SYNCHRONIZE 6608
#define ID_TB_TIMER 6800
#define ID_TB_SUSPEND 6801
#define ID_LIST_BASE 7000
#define ID_LIST_PROJECTSVIEW 7000

View File

@ -431,6 +431,7 @@ int CMainDocument::OnInit() {
m_RPCWaitDlg = NULL;
m_bWaitingForRPC = false;
m_bNeedRefresh = false;
m_bNeedTaskBarRefresh = false;
current_rpc_request.clear();
m_RPCThread = new RPCThread(this);
@ -775,9 +776,6 @@ void CMainDocument::RunPeriodicRPCs() {
int currentTabView = wxGetApp().GetCurrentViewPage();
// TODO: modify SimpleGUI to not do direct RPC calls when hidden / minimized
if (! ((currentTabView & VW_SGUI) || pFrame->IsShown()) ) return;
// Several functions (such as Abort, Reset, Detach) display an
// "Are you sure?" dialog before passing a pointer to a result
// or project in a demand RPC call. If Periodic RPCs continue
@ -787,7 +785,7 @@ void CMainDocument::RunPeriodicRPCs() {
//
// Note that this depends on using wxGetApp().SafeMessageBox()
// instead of wxMessageBox in all tab views.
if (wxGetApp().IsModalDialogDisplayed() && !(currentTabView & VW_SMSG)) {
if (wxGetApp().IsModalDialogDisplayed() && (currentTabView != (VW_SGUI | VW_SMSG)) ) {
return;
}
@ -802,13 +800,30 @@ void CMainDocument::RunPeriodicRPCs() {
request.which_rpc = RPC_GET_CC_STATUS;
request.arg1 = &async_status_buf;
request.exchangeBuf = &status;
request.rpcType = RPC_TYPE_ASYNC_NO_REFRESH;
request.rpcType = RPC_TYPE_ASYNC_WITH_UPDATE_TASKBAR_ICON_AFTER;
request.completionTime = &m_dtCachedCCStatusTimestamp;
request.resultPtr = &m_iGet_status_rpc_result;
RequestRPC(request);
}
// *********** RPC_GET_MESSAGES **************
request.clear();
request.which_rpc = RPC_GET_MESSAGES;
// m_iMessageSequenceNumber could change between request and execution
// of RPC, so pass in a pointer rather than its value
request.arg1 = &m_iMessageSequenceNumber;
request.arg2 = &messages;
// request.arg2 = &async_messages_buf;
// request.exchangeBuf = &messages;
request.rpcType = (currentTabView & VW_MSGS) ?
RPC_TYPE_ASYNC_WITH_REFRESH_AFTER : RPC_TYPE_ASYNC_WITH_UPDATE_MESSAGE_LIST_AFTER;
request.completionTime = NULL;
request.resultPtr = &m_iGet_messages_rpc_result;
RequestRPC(request);
ts = dtNow - m_dtCachedStateTimestamp;
if (ts.GetSeconds() >= STATERPC_INTERVAL) {
@ -835,7 +850,10 @@ void CMainDocument::RunPeriodicRPCs() {
RequestRPC(request);
}
// TODO: modify SimpleGUI to not do direct RPC calls when hidden / minimized
if (! ((currentTabView & VW_SGUI) || pFrame->IsShown()) ) return;
// *********** RPC_GET_PROJECT_STATUS1 **************
if (currentTabView & VW_PROJ) {
@ -852,7 +870,7 @@ void CMainDocument::RunPeriodicRPCs() {
RequestRPC(request);
}
}
// *********** RPC_GET_RESULTS **************
if (currentTabView & VW_TASK) {
@ -887,26 +905,6 @@ void CMainDocument::RunPeriodicRPCs() {
}
}
// *********** RPC_GET_MESSAGES **************
if (currentTabView & (VW_MSGS | VW_SGUI)) {
request.clear();
request.which_rpc = RPC_GET_MESSAGES;
// m_iMessageSequenceNumber could change between request and execution
// of RPC, so pass in a pointer rather than its value
request.arg1 = &m_iMessageSequenceNumber;
request.arg2 = &messages;
// request.arg2 = &async_messages_buf;
// request.exchangeBuf = &messages;
request.rpcType = (currentTabView & VW_SGUI) ?
RPC_TYPE_ASYNC_NO_REFRESH : RPC_TYPE_ASYNC_WITH_REFRESH_AFTER;
request.completionTime = NULL;
request.resultPtr = &m_iGet_messages_rpc_result;
RequestRPC(request);
}
// *********** RPC_GET_STATISTICS **************
if (currentTabView & VW_STAT) {
@ -1700,6 +1698,7 @@ int CMainDocument::WorkAbort(std::string& strProjectURL, std::string& strName) {
// Call this only when message buffer is stable
// Note: This must not call any rpcs.
int CMainDocument::CachedMessageUpdate() {
static bool in_this_func = false;

View File

@ -180,10 +180,12 @@ public:
void HandleCompletedRPC();
ASYNC_RPC_REQUEST* GetCurrentRPCRequest() { return &current_rpc_request; }
bool WaitingForRPC() { return m_bWaitingForRPC; }
wxDialog* GetRPCWaitDialog() { return m_RPCWaitDlg; }
// void TestAsyncRPC(); // For testing Async RPCs
RPCThread* m_RPCThread;
wxCriticalSection m_critsect;
bool m_bNeedRefresh;
bool m_bNeedTaskBarRefresh;
private:
int CopyProjectsToStateFile(PROJECTS& p, CC_STATE& state);