void CTabStack::RecheckPassive() { if (mn_UpdatePos < mn_Used) { // Освободить все элементы за mn_UpdatePos int i = mn_UpdatePos; DEBUGTEST(int iPrev = mn_Used); while (i < mn_Used) { CTabID *pTab = mpp_Stack[i]; if (pTab) { _ASSERTE(pTab->Info.pVCon!=NULL); if (abRConTabs && pTab->Info.pVCon) { bool bVConValid = false, bPidValid = false, bPassive = false; // Only for RCon->tabs.m_Tabs we must to check, if tab is: // 'Still Alive' // 'Hidden' (Another started Far hides editor/viewer of parent Far) // 'Terminated' (Editor/viewer was closed or Far instance terminated) CVConGroup::CheckTabValid(pTab, bVConValid, bPidValid, bPassive); if (bPidValid) { if (bPassive) { // Пока оставить этот таб i++; continue; } } } // If we get here - tab was terminated if (abRConTabs) pTab->Info.Status = tisInvalid; #ifdef TAB_REF_PLACE pTab->DelPlace(m_rp); #endif // Kill this tab pTab->Release(); mpp_Stack[i] = NULL; } DEBUGTEST(iPrev = mn_Used); PRAGMA_ERROR("FAIL. Нужно убрать из стека все NULL-ячейки"); TabDeleted(pUpdateLock, i); _ASSERTE(mn_Used < iPrev); } mn_Used = mn_UpdatePos; } }
// Возвращает "true" если были изменения в КОЛИЧЕСТВЕ табов (ЗДЕСЬ больше ничего не проверяется) bool CTabStack::UpdateEnd(HANDLE hUpdate, DWORD anActiveFarPID) { MSectionLockSimple* pUpdateLock = (MSectionLockSimple*)hUpdate; // Функция должна вызваться ТОЛЬКО между UpdateBegin & UpdateEnd if (mn_UpdatePos < 0) { _ASSERTE(mn_UpdatePos>=0); return false; } bool bVConClosed = false; if (!mb_FarUpdateMode && (mn_UpdatePos == 0)) { if (!CVConGroup::isVConExists(0)) { bVConClosed = true; } else { // Фукнция UpdateFarWindow должна была быть вызвана хотя бы раз! //UpdateFarWindow(CVirtualConsole* apVCon, LPCWSTR asName, int anType, int anPID, int anFarWindowID, int anViewEditID, CEFarWindowType anFlags) _ASSERTE(mn_UpdatePos>0 || CVConGroup::GetConCount()==0); pUpdateLock->Unlock(); delete pUpdateLock; mn_UpdatePos = -1; return false; } } bool bChanged = (mn_Used != mn_UpdatePos); #if 1 _ASSERTE(pUpdateLock->isLocked()); #else pUpdateLock->RelockExclusive(); #endif if (mb_FarUpdateMode) { _ASSERTE(mn_UpdatePos > 0); // Все табы ПОСЛЕ последнего добавленного/обновленного - помечаем неактивными for (int i = mn_UpdatePos; i < mn_Used; i++) { CTabID *pTab = mpp_Stack[i]; if (pTab && (pTab->Info.Status != tisInvalid)) { pTab->Info.Status = tisPassive; } } // Активен Far? ВСЕ tisPassive табы этого Far-а - разрушаем if (anActiveFarPID) { for (int i = 0; i < mn_Used; i++) { CTabID *pTab = mpp_Stack[i]; // Проверяем только табы активного фара (пассивные [Far -> Far -> Far] не трогаем) if (!pTab || (pTab->Info.nPID != anActiveFarPID)) continue; // Панели и табы с не пассивным статусом - не трогаем if ((pTab->Type() == fwt_Panels) || (pTab->Info.Status != tisPassive)) continue; // Таб (редактор/вьювер) был закрыт, разрушаем _ASSERTE(pTab->Type()==fwt_Editor || pTab->Type()==fwt_Viewer); // Kill this tab pTab->Info.Status = tisInvalid; } } } else { // Для самого таббара - весь хвост просто выкинуть из списка, но сами CTabID не разрушать (tisInvalid не ставить) for (int i = mn_UpdatePos; i < mn_Used; i++) { CTabID *pTab = mpp_Stack[i]; if (pTab) { if (!CVConGroup::isValid((CVirtualConsole*)pTab->Info.pVCon)) pTab->Info.Status = tisInvalid; #ifdef TAB_REF_PLACE pTab->DelPlace(m_rp); #endif pTab->Release(); // Remove from list mpp_Stack[i] = NULL; bChanged = true; } } } for (int i = 0; i < mn_Used; i++) { CTabID *pTab = mpp_Stack[i]; // Kill all invalid tabs if (!pTab || (pTab->Info.Status != tisInvalid)) continue; #ifdef TAB_REF_PLACE pTab->DelPlace(m_rp); #endif pTab->Release(); // Remove from list mpp_Stack[i] = NULL; bChanged = true; } CleanNulls(); pUpdateLock->Unlock(); delete pUpdateLock; return bChanged; }
// Должен вызываться только из CRealConsole! // Возвращает "true" если были изменения bool CTabStack::UpdateFarWindow(HANDLE hUpdate, CVirtualConsole* apVCon, LPCWSTR asName, CEFarWindowType anType, int anPID, int anFarWindowID, int anViewEditID, CTab& rActiveTab) { MSectionLockSimple* pUpdateLock = (MSectionLockSimple*)hUpdate; // Функция должна вызваться ТОЛЬКО между UpdateBegin & UpdateEnd if (mn_UpdatePos < 0 || !pUpdateLock) { _ASSERTE(mn_UpdatePos>=0); _ASSERTE(pUpdateLock!=NULL); return false; } bool bChanged = false; CTabID* pTab = NULL; mb_FarUpdateMode = true; // Теперь - поехали обновлять. Правила такие: // 1. Новая вкладка в ФАР может появиться ТОЛЬКО в конце // 2. Закрыта может быть любая вкладка // 3. панели НЕ должны перебиваться на редактор при запуске "far /e" // 4. и вообще, первый таб мог быть добавлен изначально как редактор! int i = mn_UpdatePos; while (i < mn_Used) { if (!mpp_Stack[i]) { i++; continue; } if (mpp_Stack[i]->IsEqual(apVCon, asName, anType, anPID, anViewEditID, fwt_TypeMask)) { // OK, таб совпадает pTab = mpp_Stack[i]; // Refresh status and title if (pTab->Set(asName, anType, anPID, anFarWindowID, anViewEditID, fwt_UpdateFlags)) bChanged = true; _ASSERTE(pTab->Info.Status == tisValid); if (anType & fwt_CurrentFarWnd) rActiveTab.Init(pTab); mn_UpdatePos = i+1; // Закончили break; } // Tab was closed or gone to background bChanged = true; mpp_Stack[i]->Info.Status = tisPassive; i++; } // Если таб новый if (pTab == NULL) { // это новая вкладка, добавляемая в конец pTab = new CTabID(apVCon, asName, anType, anPID, anFarWindowID, anViewEditID); _ASSERTE(pTab->RefCount()==1); _ASSERTE(mn_Used == i); i = AppendInt(pTab, FALSE/*abMoveFirst*/, pUpdateLock); _ASSERTE(pTab->RefCount()==2); if (anType & fwt_CurrentFarWnd) rActiveTab.Init(pTab); pTab->Release(); bChanged = true; mn_UpdatePos = i+1; } _ASSERTE(mn_UpdatePos>=1 && mn_UpdatePos<=mn_Used); return bChanged; }