bool CTabStack::GetNextTab(const CTabID* pTab, BOOL abForward, /*OUT*/ CTab& rTab) { MSectionLockSimple SC; SC.Lock(mpc_Section); CTabID* pNextTab = NULL; for (int i = 0; i < mn_Used; i++) { if (mpp_Stack[i] == pTab) { if (abForward) { if ((i + 1) < mn_Used) pNextTab = mpp_Stack[i+1]; } else { if (i > 0) pNextTab = mpp_Stack[i-1]; } break; } } rTab.Init(pNextTab); SC.Unlock(); return (pNextTab!=NULL); }
bool CTabStack::GetTabByIndex(int anIndex, /*OUT*/ CTab& rTab) { MSectionLockSimple SC; SC.Lock(mpc_Section); int iReal = GetVisualToRealIndex(anIndex); if (iReal >= 0 && iReal < mn_Used) { rTab.Init(mpp_Stack[iReal]); } else { rTab.Init(NULL); } SC.Unlock(); return (rTab.Tab() != NULL); }
// Убьет из стека отсутствующих и поместит tab на верх стека bool CTabBarClass::AddStack(CTab& tab) { if (tab.Tab() == mp_DummyTab) return false; bool bStackChanged = false; _ASSERTE(isMainThread()); bool lbExist = false; if (!m_TabStack.empty()) { int iter = 0; while (iter < m_TabStack.size()) { if (m_TabStack[iter] == tab.Tab()) { if ((iter > 0) && !IsInSwitch()) { CTabID* pTab = m_TabStack[iter]; m_TabStack.erase(iter); m_TabStack.insert(0, pTab); bStackChanged = true; } lbExist = true; break; } ++iter; } } // поместить наверх стека if (!lbExist) { CTabID* pTab = tab.AddRef("TabBar.cpp:m_TabStack",0); m_TabStack.insert(0, pTab); bStackChanged = true; } return bStackChanged; }
int CTabBarClass::PrepareTab(CTab& pTab, CVirtualConsole *apVCon) { int iTabIcon = -1; #ifdef _DEBUG if (this != gpConEmu->mp_TabBar) { _ASSERTE(this == gpConEmu->mp_TabBar); } #endif MCHKHEAP // get file name TCHAR dummy[MAX_PATH*2]; TCHAR fileName[MAX_PATH+4]; fileName[0] = 0; TCHAR szFormat[32]; TCHAR szEllip[MAX_PATH+1]; //wchar_t /**tFileName=NULL,*/ *pszNo=NULL, *pszTitle=NULL; int nSplit = 0; int nMaxLen = 0; //gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; int origLength = 0; //_tcslen(tFileName); CRealConsole* pRCon = apVCon ? apVCon->RCon() : NULL; bool bIsFar = pRCon ? pRCon->isFar() : false; // Far 4040 - new "Desktop" window type has "0" index if (apVCon && (pTab->Info.nFarWindowID == 0 || pTab->Type() == fwt_Panels)) { iTabIcon = apVCon->RCon()->GetRootProcessIcon(); } LPCWSTR pszTabName = pRCon->GetTabTitle(pTab); if (pTab->Name.Empty() || (pTab->Type() == fwt_Panels)) { //_tcscpy(szFormat, _T("%s")); lstrcpyn(szFormat, bIsFar ? gpSet->szTabPanels : gpSet->szTabConsole, countof(szFormat)); nMaxLen = gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; lstrcpyn(fileName, pszTabName, countof(fileName)); if (gpSet->pszTabSkipWords && *gpSet->pszTabSkipWords) { StripWords(fileName, gpSet->pszTabSkipWords); } origLength = _tcslen(fileName); //if (origLength>6) { // // Чтобы в заголовке было что-то вроде "{C:\Program Fil...- Far" // // вместо "{C:\Program F...} - Far" // После добавления суффиков к заголовку фара - оно уже влезать не будет в любом случае... Так что если панели - '...' строго ставить в конце // if (lstrcmp(tFileName + origLength - 6, L" - Far") == 0) // nSplit = nMaxLen - 6; //} } else { LPTSTR tFileName = NULL; if (GetFullPathName(pszTabName, countof(dummy), dummy, &tFileName) && tFileName && *tFileName) lstrcpyn(fileName, tFileName, countof(fileName)); else lstrcpyn(fileName, pszTabName, countof(fileName)); if (pTab->Type() == fwt_Editor) { if (pTab->Flags() & fwt_ModifiedFarWnd) lstrcpyn(szFormat, gpSet->szTabEditorModified, countof(szFormat)); else lstrcpyn(szFormat, gpSet->szTabEditor, countof(szFormat)); } else if (pTab->Type() == fwt_Viewer) { lstrcpyn(szFormat, gpSet->szTabViewer, countof(szFormat)); } else { _ASSERTE(FALSE && "Must be processed in previous branch"); lstrcpyn(szFormat, bIsFar ? gpSet->szTabPanels : gpSet->szTabConsole, countof(szFormat)); } } // restrict length if (!nMaxLen) nMaxLen = gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; if (!origLength) origLength = _tcslen(fileName); if (nMaxLen<15) nMaxLen=15; else if (nMaxLen>=MAX_PATH) nMaxLen=MAX_PATH-1; if (origLength > nMaxLen) { /*_tcsnset(fileName, _T('\0'), MAX_PATH); _tcsncat(fileName, tFileName, 10); _tcsncat(fileName, _T("..."), 3); _tcsncat(fileName, tFileName + origLength - 10, 10);*/ //if (!nSplit) // nSplit = nMaxLen*2/3; //// 2009-09-20 Если в заголовке нет расширения (отсутствует точка) //const wchar_t* pszAdmin = gpSet->szAdminTitleSuffix; //const wchar_t* pszFrom = tFileName + origLength - (nMaxLen - nSplit); //if (!wcschr(pszFrom, L'.') && (*pszAdmin && !wcsstr(tFileName, pszAdmin))) //{ // // то троеточие ставить в конец, а не середину // nSplit = nMaxLen; //} // "{C:\Program Files} - Far 2.1283 Administrator x64" // После добавления суффиков к заголовку фара - оно уже влезать не будет в любом случае... Так что если панели - '...' строго ставить в конце nSplit = nMaxLen; _tcsncpy(szEllip, fileName, nSplit); szEllip[nSplit]=0; szEllip[nSplit] = L'\x2026' /*"…"*/; szEllip[nSplit+1] = 0; //_tcscat(szEllip, L"\x2026" /*"…"*/); //_tcscat(szEllip, tFileName + origLength - (nMaxLen - nSplit)); //tFileName = szEllip; lstrcpyn(fileName, szEllip, countof(fileName)); } // szFormat различается для Panel/Viewer(*)/Editor(*) // Пример: "%i-[%s] *" ////pszNo = wcsstr(szFormat, L"%i"); ////pszTitle = wcsstr(szFormat, L"%s"); ////if (pszNo == NULL) //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, tFileName); ////else if (pszNo < pszTitle || pszTitle == NULL) //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, pTab->Pos, tFileName); ////else //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, tFileName, pTab->Pos); //wcscpy(pTab->Name, fileName); const TCHAR* pszFmt = szFormat; TCHAR* pszDst = dummy; TCHAR* pszStart = pszDst; TCHAR* pszEnd = dummy + countof(dummy) - 1; // в конце еще нужно зарезервировать место для '\0' if (!pszFmt || !*pszFmt) { pszFmt = _T("%s"); } *pszDst = 0; bool bRenamedTab = false; if (pTab->Flags() & fwt_Renamed) { if (wcsstr(pszFmt, L"%s") == NULL) { if (wcsstr(pszFmt, L"%n") != NULL) bRenamedTab = true; else pszFmt = _T("%s"); } } TCHAR szTmp[64]; CmdArg szArg; bool bAppendAdmin = gpSet->isAdminSuffix() && (pTab->Flags() & fwt_Elevated); while (*pszFmt && pszDst < pszEnd) { if (*pszFmt == _T('%')) { pszFmt++; LPCTSTR pszText = NULL; switch (*pszFmt) { case _T('s'): case _T('S'): pszText = fileName; break; case _T('i'): case _T('I'): _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%i"), pTab->Info.nIndex); pszText = szTmp; break; case _T('p'): case _T('P'): if (!apVCon || !apVCon->RCon()) { wcscpy_c(szTmp, _T("?")); } else { _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%u"), apVCon->RCon()->GetActivePID()); } pszText = szTmp; break; case _T('c'): case _T('C'): { int iCon = gpConEmu->isVConValid(apVCon); if (iCon > 0) _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%u"), iCon); else wcscpy_c(szTmp, _T("?")); pszText = szTmp; } break; case _T('n'): case _T('N'): { pszText = bRenamedTab ? fileName : pRCon ? pRCon->GetActiveProcessName() : NULL; wcscpy_c(szTmp, (pszText && *pszText) ? pszText : L"?"); pszText = szTmp; } break; case _T('d'): case _T('D'): { pszText = pRCon ? pRCon->GetConsoleCurDir(szArg) : NULL; if (!pszText || !*pszText) pszText = L"?"; } break; case _T('a'): case _T('A'): pszText = bAppendAdmin ? gpSet->szAdminTitleSuffix : NULL; bAppendAdmin = false; break; case _T('%'): pszText = L"%"; break; case 0: pszFmt--; break; } pszFmt++; if (pszText) { if ((*(pszDst-1) == L' ') && (*pszText == L' ')) pszText = SkipNonPrintable(pszText); while (*pszText && pszDst < pszEnd) { *(pszDst++) = *(pszText++); } } } else if ((pszDst > pszStart) && (*(pszDst-1) == L' ') && (*pszFmt == L' ')) { pszFmt++; // Avoid adding sequential spaces (e.g. if some macros was empty) } else { *(pszDst++) = *(pszFmt++); } } // Fin. Append smth else? if (bAppendAdmin) { LPCTSTR pszText = gpSet->szAdminTitleSuffix; if (pszText) { while (*pszText && pszDst < pszEnd) { *(pszDst++) = *(pszText++); } } } *pszDst = 0; #ifdef _DEBUG if (dummy[0] && *(pszDst-1) == L' ') *pszDst = 0; #endif pTab->SetLabel(dummy); MCHKHEAP; return iTabIcon; }
// Должен вызываться только из 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; }
bool CTabStack::RefreshFarStatus(DWORD nFarPID, CTab& rActiveTab, int& rnActiveIndex, int& rnActiveCount, bool& rbHasModalTab) { MSectionLockSimple SC; SC.Lock(mpc_Section); // Сразу Exclusive lock bool bChanged = false; int iCount = 0; int iActive = -1; int iModal = -1; int iFirstAvailable = -1; int iFirstPanels = -1; DEBUGTEST(int iPanelsCount = 0); bool bPanels; for (int i = 0; i < mn_Used; i++) { if (!mpp_Stack[i]) continue; // fwt_Panels всегда должен быть bPanels = (mpp_Stack[i]->Type() == fwt_Panels); #ifdef _DEBUG if (bPanels) iPanelsCount++; #endif // When returning to Far - mark its editors/viewers as Valid if (nFarPID && (mpp_Stack[i]->Info.nPID == nFarPID)) { if (mpp_Stack[i]->Info.Status == tisPassive) { mpp_Stack[i]->Info.Status = tisValid; bChanged = true; } } else if (!bPanels) { if (mpp_Stack[i]->Info.Status == tisValid) { mpp_Stack[i]->Info.Status = tisPassive; bChanged = true; } } // Find active tabs if (mpp_Stack[i]->Info.Status == tisValid) { iCount++; if (mpp_Stack[i]->Info.Type & fwt_CurrentFarWnd) { _ASSERTE(iActive == -1 && "Only one active tab per console!"); iActive = i; } if (mpp_Stack[i]->Info.Type & fwt_ModalFarWnd) { _ASSERTE((mpp_Stack[i]->Info.Type & fwt_CurrentFarWnd) && "Modal must be current"); iModal = i; } if (iFirstAvailable < 0) { iFirstAvailable = i; } } else if ((iFirstPanels < 0) && bPanels && (mpp_Stack[i]->Info.Status == tisPassive)) { // May be when returning from "far /e ..." to cmd or another std Far instance iFirstPanels = i; } } _ASSERTE(iPanelsCount==1); // Во время закрытия фара могут быть пертурбации if (iActive < 0) { if (iModal >= 0) { iActive = iModal; } else if (iFirstAvailable >= 0) { iActive = iFirstAvailable; } else if (iFirstPanels >= 0) { _ASSERTE(iCount==0); iActive = iFirstPanels; // There was no one "Active" tab. Mark panels tab as active! _ASSERTE(nFarPID == 0); // returning from "far /e ..."? _ASSERTE(mpp_Stack[iFirstPanels] != NULL); // Protected with CS, no need to check mpp_Stack[iFirstPanels]->Info.Status = tisValid; iCount = 1; } // Check return value if (!bChanged) bChanged = (iActive >= 0); } _ASSERTE(iCount>0 && "At least one tab must be available"); // Во время закрытия фара может возникать... if ((iActive >= 0) && !(mpp_Stack[iActive]->Info.Type & fwt_CurrentFarWnd)) { mpp_Stack[iActive]->Info.Type |= fwt_CurrentFarWnd; } rbHasModalTab = (iModal >= 0); rnActiveCount = iCount; rActiveTab.Init((iActive >= 0) ? mpp_Stack[iActive] : NULL); rnActiveIndex = iActive; return bChanged; }
size_t CConEmuCtrl::GetOpenedTabs(CESERVER_REQ_GETALLTABS::TabInfo*& pTabs) { _ASSERTE(pTabs==NULL); int nConCount = gpConEmu->GetConCount(); int nActiveCon = gpConEmu->ActiveConNum(); size_t cchMax = nConCount*16; size_t cchCount = 0; CVirtualConsole* pVCon; pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)calloc(cchMax, sizeof(*pTabs)); for (int V = 0; (pVCon = gpConEmu->GetVCon(V)) != NULL; V++) { if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } CRealConsole* pRCon = pVCon->RCon(); if (!pRCon) continue; CTab tab; wchar_t szMark[6]; for (int T = 0; pRCon->GetTab(T, tab); T++) { if (cchCount >= cchMax) { pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)realloc(pTabs, (cchMax+32)*sizeof(*pTabs)); if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } cchMax += 32; _ASSERTE(cchCount<cchMax); } pTabs[cchCount].ActiveConsole = (V == nActiveCon); pTabs[cchCount].ActiveTab = ((tab->Flags() & fwt_CurrentFarWnd) == fwt_CurrentFarWnd); pTabs[cchCount].Disabled = ((tab->Flags() & fwt_Disabled) == fwt_Disabled); pTabs[cchCount].ConsoleIdx = V; pTabs[cchCount].TabIdx = T; // Text //wcscpy_c(szMark, tab.Modified ? L" * " : L" "); switch (tab->Type()) { case fwt_Editor: wcscpy_c(szMark, (tab->Flags() & fwt_ModifiedFarWnd) ? L" * " : L" E "); break; case fwt_Viewer: wcscpy_c(szMark, L" V "); break; default: wcscpy_c(szMark, L" "); } if (V == nActiveCon) { if (T <= 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/&%i]%s", V+1, T, szMark); //else if (T == 9) // _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/1&0]%s", V+1, szMark); else _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T, szMark); } else { _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T, szMark); } int nCurLen = lstrlen(pTabs[cchCount].Title); lstrcpyn(pTabs[cchCount].Title+nCurLen, tab->Name.Ptr(), countof(pTabs[cchCount].Title)-nCurLen); cchCount++; } } return cchCount; }