Backed out bug 313403. (merge)

This commit is contained in:
Vladimir Vukicevic 2008-08-20 13:28:49 -07:00
commit 362a1a5270

View File

@ -257,6 +257,10 @@ PRInt32 GetWindowsVersion()
return version;
}
// Pick some random timer ID. Is there a better way?
#define NS_FLASH_TIMER_ID 0x011231984
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
@ -424,6 +428,119 @@ static PRBool is_vk_down(int vk)
#endif // #ifndef APPCOMMAND_BROWSER_BACKWARD
/* This object maintains a correlation between attention timers and the
windows to which they belong. It's lighter than a hashtable (expected usage
is really just one at a time) and allows nsWindow::GetNSWindowPtr
to remain private. */
class nsAttentionTimerMonitor {
public:
nsAttentionTimerMonitor() : mHeadTimer(0) { }
~nsAttentionTimerMonitor() {
TimerInfo *current, *next;
for (current = mHeadTimer; current; current = next) {
next = current->next;
delete current;
}
}
void AddTimer(HWND timerWindow, HWND flashWindow, PRInt32 maxFlashCount, UINT timerID) {
TimerInfo *info;
PRBool newInfo = PR_FALSE;
info = FindInfo(timerWindow);
if (!info) {
info = new TimerInfo;
newInfo = PR_TRUE;
}
if (info) {
info->timerWindow = timerWindow;
info->flashWindow = flashWindow;
info->maxFlashCount = maxFlashCount;
info->flashCount = 0;
info->timerID = timerID;
info->hasFlashed = PR_FALSE;
info->next = 0;
if (newInfo)
AppendTimer(info);
}
}
HWND GetFlashWindowFor(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
return info ? info->flashWindow : 0;
}
PRInt32 GetMaxFlashCount(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
return info ? info->maxFlashCount : -1;
}
PRInt32 GetFlashCount(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
return info ? info->flashCount : -1;
}
void IncrementFlashCount(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
++(info->flashCount);
}
void KillTimer(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
if (info) {
// make sure it's unflashed and kill the timer
if (info->hasFlashed)
::FlashWindow(info->flashWindow, FALSE);
::KillTimer(info->timerWindow, info->timerID);
RemoveTimer(info);
delete info;
}
}
void SetFlashed(HWND timerWindow) {
TimerInfo *info = FindInfo(timerWindow);
if (info)
info->hasFlashed = PR_TRUE;
}
private:
struct TimerInfo {
HWND timerWindow,
flashWindow;
UINT timerID;
PRInt32 maxFlashCount;
PRInt32 flashCount;
PRBool hasFlashed;
TimerInfo *next;
};
TimerInfo *FindInfo(HWND timerWindow) {
TimerInfo *scan;
for (scan = mHeadTimer; scan; scan = scan->next)
if (scan->timerWindow == timerWindow)
break;
return scan;
}
void AppendTimer(TimerInfo *info) {
if (!mHeadTimer)
mHeadTimer = info;
else {
TimerInfo *scan, *last;
for (scan = mHeadTimer; scan; scan = scan->next)
last = scan;
last->next = info;
}
}
void RemoveTimer(TimerInfo *info) {
TimerInfo *scan, *last = 0;
for (scan = mHeadTimer; scan && scan != info; scan = scan->next)
last = scan;
if (scan) {
if (last)
last->next = scan->next;
else
mHeadTimer = scan->next;
}
}
TimerInfo *mHeadTimer;
};
static nsAttentionTimerMonitor *gAttentionTimerMonitor = 0;
HWND nsWindow::GetTopLevelHWND(HWND aWnd, PRBool aStopOnFirstTopLevel)
{
HWND curWnd = aWnd;
@ -1316,6 +1433,8 @@ NS_METHOD nsWindow::Destroy()
if (mWnd) {
// prevent the widget from causing additional events
mEventCallback = nsnull;
if (gAttentionTimerMonitor)
gAttentionTimerMonitor->KillTimer(mWnd);
// if IME is disabled, restore it.
if (mOldIMC) {
@ -7352,6 +7471,38 @@ void nsWindow::GetCompositionWindowPos(HIMC hIMC, PRUint32 aEventType, COMPOSITI
cpForm->rcArea.bottom = cpForm->ptCurrentPos.y + event.theReply.mCursorPosition.height;
}
// This function is called on a timer to do the flashing. It simply toggles the flash
// status until the window comes to the foreground.
static VOID CALLBACK nsGetAttentionTimerFunc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
// flash the window until we're in the foreground.
if (::GetForegroundWindow() != hwnd)
{
// flash the outermost owner
HWND flashwnd = gAttentionTimerMonitor->GetFlashWindowFor(hwnd);
PRInt32 maxFlashCount = gAttentionTimerMonitor->GetMaxFlashCount(hwnd);
PRInt32 flashCount = gAttentionTimerMonitor->GetFlashCount(hwnd);
if (maxFlashCount > 0) {
// We have a max flash count, if we haven't met it yet, flash again.
if (flashCount < maxFlashCount) {
::FlashWindow(flashwnd, TRUE);
gAttentionTimerMonitor->IncrementFlashCount(hwnd);
}
else
gAttentionTimerMonitor->KillTimer(hwnd);
}
else {
// The caller didn't specify a flash count.
::FlashWindow(flashwnd, TRUE);
}
gAttentionTimerMonitor->SetFlashed(hwnd);
}
else
gAttentionTimerMonitor->KillTimer(hwnd);
}
// Draw user's attention to this window until it comes to foreground.
NS_IMETHODIMP
nsWindow::GetAttention(PRInt32 aCycleCount)
@ -7360,24 +7511,28 @@ nsWindow::GetAttention(PRInt32 aCycleCount)
if (!mWnd)
return NS_ERROR_NOT_INITIALIZED;
// Don't flash if the flash count is 0 or if the
// top level window is already active.
if (aCycleCount == 0 || ::GetForegroundWindow() == GetTopLevelHWND(mWnd))
// Don't flash if the flash count is 0.
if (aCycleCount == 0)
return NS_OK;
DWORD defaultCycleCount = 0;
::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0);
HWND flashWnd = mWnd;
while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER))
flashWnd = ownerWnd;
// timer is on the parentmost window; window to flash is its ownermost
HWND timerwnd = GetTopLevelHWND(mWnd);
HWND flashwnd = timerwnd;
HWND nextwnd;
while ((nextwnd = ::GetWindow(flashwnd, GW_OWNER)) != 0)
flashwnd = nextwnd;
// If window is in foreground, no notification is necessary.
if (::GetForegroundWindow() != timerwnd) {
// kick off a timer that does single flash until the window comes to the foreground
if (!gAttentionTimerMonitor)
gAttentionTimerMonitor = new nsAttentionTimerMonitor;
if (gAttentionTimerMonitor) {
gAttentionTimerMonitor->AddTimer(timerwnd, flashwnd, aCycleCount, NS_FLASH_TIMER_ID);
::SetTimer(timerwnd, NS_FLASH_TIMER_ID, GetCaretBlinkTime(), (TIMERPROC)nsGetAttentionTimerFunc);
}
}
FLASHWINFO flashInfo;
ZeroMemory(&flashInfo, sizeof(FLASHWINFO));
flashInfo.cbSize = sizeof(FLASHWINFO);
flashInfo.hwnd = flashWnd;
flashInfo.dwFlags = FLASHW_ALL;
flashInfo.uCount = aCycleCount > 0 ? aCycleCount : defaultCycleCount;
::FlashWindowEx(&flashInfo);
return NS_OK;
}