Integrate unfix.org's IPv6 patches up to level 10, with rather a lot
[u/mdw/putty] / windows / window.c
index ccebea7..17aaf1a 100644 (file)
@@ -92,17 +92,12 @@ static int offset_width, offset_height;
 static int was_zoomed = 0;
 static int prev_rows, prev_cols;
   
-static int pending_netevent = 0;
-static WPARAM pend_netevent_wParam = 0;
-static LPARAM pend_netevent_lParam = 0;
-static void enact_pending_netevent(void);
+static void enact_netevent(WPARAM, LPARAM);
 static void flash_window(int mode);
 static void sys_cursor_update(void);
 static int is_shift_pressed(void);
 static int get_fullscreen_rect(RECT * ss);
 
-static time_t last_movement = 0;
-
 static int caret_x = -1, caret_y = -1;
 
 static int kbd_codepage;
@@ -117,6 +112,9 @@ static int session_closed;
 static const struct telnet_special *specials;
 static int n_specials;
 
+#define TIMING_TIMER_ID 1234
+static long timing_next_time;
+
 static struct {
     HMENU menu;
     int specials_submenu_pos;
@@ -160,11 +158,13 @@ static enum {
 } und_mode;
 static int descent;
 
-#define NCOLOURS 24
-static COLORREF colours[NCOLOURS];
+#define NCFGCOLOURS 22
+#define NEXTCOLOURS 240
+#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)
+static COLORREF colours[NALLCOLOURS];
 static HPALETTE pal;
 static LPLOGPALETTE logpal;
-static RGBTRIPLE defpal[NCOLOURS];
+static RGBTRIPLE defpal[NALLCOLOURS];
 
 static HWND hwnd;
 
@@ -542,9 +542,20 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        }
 
        /*
-        * Trim a colon suffix off the hostname if it's there.
+        * Trim a colon suffix off the hostname if it's there. In
+        * order to protect IPv6 address literals against this
+        * treatment, we do not do this if there's _more_ than one
+        * colon.
         */
-       cfg.host[strcspn(cfg.host, ":")] = '\0';
+       {
+           char *c = strchr(cfg.host, ':');
+
+           if (c) {
+               char *d = strchr(c+1, ':');
+               if (!d)
+                   *c = '\0';
+           }
+       }
 
        /*
         * Remove any remaining whitespace from the hostname.
@@ -590,10 +601,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 
     memset(&ucsdata, 0, sizeof(ucsdata));
 
-    term = term_init(&cfg, &ucsdata, NULL);
-    logctx = log_init(NULL, &cfg);
-    term_provide_logctx(term, logctx);
-
     cfgtopalette();
 
     /*
@@ -607,9 +614,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     font_height = 20;
     extra_width = 25;
     extra_height = 28;
-    term_size(term, cfg.height, cfg.width, cfg.savelines);
-    guess_width = extra_width + font_width * term->cols;
-    guess_height = extra_height + font_height * term->rows;
+    guess_width = extra_width + font_width * cfg.width;
+    guess_height = extra_height + font_height * cfg.height;
     {
        RECT r;
                get_fullscreen_rect(&r);
@@ -637,6 +643,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     }
 
     /*
+     * Initialise the terminal. (We have to do this _after_
+     * creating the window, since the terminal is the first thing
+     * which will call schedule_timer(), which will in turn call
+     * timer_change_notify() which will expect hwnd to exist.)
+     */
+    term = term_init(&cfg, &ucsdata, NULL);
+    logctx = log_init(NULL, &cfg);
+    term_provide_logctx(term, logctx);
+    term_size(term, cfg.height, cfg.width, cfg.savelines);
+
+    /*
      * Initialise the fonts, simultaneously correcting the guesses
      * for font_{width,height}.
      */
@@ -772,34 +789,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     logpal = NULL;
     init_palette();
 
-    term->has_focus = (GetForegroundWindow() == hwnd);
+    term_set_focus(term, GetForegroundWindow() == hwnd);
     UpdateWindow(hwnd);
 
     if (GetMessage(&msg, NULL, 0, 0) == 1) {
-       int timer_id = 0, long_timer = 0;
-
        while (msg.message != WM_QUIT) {
-           /* Sometimes DispatchMessage calls routines that use their own
-            * GetMessage loop, setup this timer so we get some control back.
-            *
-            * Also call term_update() from the timer so that if the host
-            * is sending data flat out we still do redraws.
-            */
-           if (timer_id && long_timer) {
-               KillTimer(hwnd, timer_id);
-               long_timer = timer_id = 0;
-           }
-           if (!timer_id)
-               timer_id = SetTimer(hwnd, 1, 20, NULL);
            if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
                DispatchMessage(&msg);
-
-           /* Make sure we blink everything that needs it. */
-           term_blink(term, 0);
-
            /* Send the paste buffer if there's anything to send */
            term_paste(term);
-
            /* If there's nothing new in the queue then we can do everything
             * we've delayed, reading the socket, writing, and repainting
             * the window.
@@ -807,42 +805,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                continue;
 
-           if (pending_netevent) {
-               enact_pending_netevent();
-
-               if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-                   continue;
-           }
-
-           /* Okay there is now nothing to do so we make sure the screen is
-            * completely up to date then tell windows to call us in a little 
-            * while.
-            */
-           if (timer_id) {
-               KillTimer(hwnd, timer_id);
-               timer_id = 0;
-           }
-           HideCaret(hwnd);
-           if (GetCapture() != hwnd || 
-               (send_raw_mouse &&
-                !(cfg.mouse_override && is_shift_pressed())))
-               term_out(term);
-           term_update(term);
-           ShowCaret(hwnd);
-
-           flash_window(1);           /* maintain */
-
            /* The messages seem unreliable; especially if we're being tricky */
-           term->has_focus = (GetForegroundWindow() == hwnd);
+           term_set_focus(term, GetForegroundWindow() == hwnd);
 
-           if (term->in_vbell)
-               /* Hmm, term_update didn't want to do an update too soon ... */
-               timer_id = SetTimer(hwnd, 1, 50, NULL);
-           else if (!term->has_focus)
-               timer_id = SetTimer(hwnd, 1, 500, NULL);
-           else
-               timer_id = SetTimer(hwnd, 1, 100, NULL);
-           long_timer = 1;
+           net_pending_errors();
 
            /* There's no point rescanning everything in the message queue
             * so we do an apparently unnecessary wait here
@@ -1035,7 +1001,7 @@ void cmdline_error(char *fmt, ...)
 /*
  * Actually do the job requested by a WM_NETEVENT
  */
-static void enact_pending_netevent(void)
+static void enact_netevent(WPARAM wParam, LPARAM lParam)
 {
     static int reentering = 0;
     extern int select_result(WPARAM, LPARAM);
@@ -1044,10 +1010,8 @@ static void enact_pending_netevent(void)
     if (reentering)
        return;                        /* don't unpend the pending */
 
-    pending_netevent = FALSE;
-
     reentering = 1;
-    ret = select_result(pend_netevent_wParam, pend_netevent_lParam);
+    ret = select_result(wParam, lParam);
     reentering = 0;
 
     if (ret == 0 && !session_closed) {
@@ -1072,16 +1036,29 @@ static void cfgtopalette(void)
 {
     int i;
     static const int ww[] = {
-       6, 7, 8, 9, 10, 11, 12, 13,
-       14, 15, 16, 17, 18, 19, 20, 21,
-       0, 1, 2, 3, 4, 4, 5, 5
+       256, 257, 258, 259, 260, 261,
+       0, 8, 1, 9, 2, 10, 3, 11,
+       4, 12, 5, 13, 6, 14, 7, 15
     };
 
-    for (i = 0; i < 24; i++) {
+    for (i = 0; i < 22; i++) {
        int w = ww[i];
-       defpal[i].rgbtRed = cfg.colours[w][0];
-       defpal[i].rgbtGreen = cfg.colours[w][1];
-       defpal[i].rgbtBlue = cfg.colours[w][2];
+       defpal[w].rgbtRed = cfg.colours[i][0];
+       defpal[w].rgbtGreen = cfg.colours[i][1];
+       defpal[w].rgbtBlue = cfg.colours[i][2];
+    }
+    for (i = 0; i < NEXTCOLOURS; i++) {
+       if (i < 216) {
+           int r = i / 36, g = (i / 6) % 6, b = i % 6;
+           defpal[i+16].rgbtRed = r * 0x33;
+           defpal[i+16].rgbtGreen = g * 0x33;
+           defpal[i+16].rgbtBlue = b * 0x33;
+       } else {
+           int shade = i - 216;
+           shade = (shade + 1) * 0xFF / (NEXTCOLOURS - 216 + 1);
+           defpal[i+16].rgbtRed = defpal[i+16].rgbtGreen =
+               defpal[i+16].rgbtBlue = shade;
+       }
     }
 
     /* Override with system colours if appropriate */
@@ -1100,10 +1077,10 @@ static void systopalette(void)
     int i;
     static const struct { int nIndex; int norm; int bold; } or[] =
     {
-       { COLOR_WINDOWTEXT,     16, 17 }, /* Default Foreground */
-       { COLOR_WINDOW,         18, 19 }, /* Default Background */
-       { COLOR_HIGHLIGHTTEXT,  20, 21 }, /* Cursor Text */
-       { COLOR_HIGHLIGHT,      22, 23 }, /* Cursor Colour */
+       { COLOR_WINDOWTEXT,     256, 257 }, /* Default Foreground */
+       { COLOR_WINDOW,         258, 259 }, /* Default Background */
+       { COLOR_HIGHLIGHTTEXT,  260, 260 }, /* Cursor Text */
+       { COLOR_HIGHLIGHT,      261, 261 }, /* Cursor Colour */
     };
 
     for (i = 0; i < (sizeof(or)/sizeof(or[0])); i++) {
@@ -1132,10 +1109,10 @@ static void init_palette(void)
             */
            logpal = smalloc(sizeof(*logpal)
                             - sizeof(logpal->palPalEntry)
-                            + NCOLOURS * sizeof(PALETTEENTRY));
+                            + NALLCOLOURS * sizeof(PALETTEENTRY));
            logpal->palVersion = 0x300;
-           logpal->palNumEntries = NCOLOURS;
-           for (i = 0; i < NCOLOURS; i++) {
+           logpal->palNumEntries = NALLCOLOURS;
+           for (i = 0; i < NALLCOLOURS; i++) {
                logpal->palPalEntry[i].peRed = defpal[i].rgbtRed;
                logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen;
                logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue;
@@ -1151,12 +1128,12 @@ static void init_palette(void)
        ReleaseDC(hwnd, hdc);
     }
     if (pal)
-       for (i = 0; i < NCOLOURS; i++)
+       for (i = 0; i < NALLCOLOURS; i++)
            colours[i] = PALETTERGB(defpal[i].rgbtRed,
                                    defpal[i].rgbtGreen,
                                    defpal[i].rgbtBlue);
     else
-       for (i = 0; i < NCOLOURS; i++)
+       for (i = 0; i < NALLCOLOURS; i++)
            colours[i] = RGB(defpal[i].rgbtRed,
                             defpal[i].rgbtGreen, defpal[i].rgbtBlue);
 }
@@ -1795,6 +1772,17 @@ static int is_shift_pressed(void)
 
 static int resizing;
 
+void notify_remote_exit(void *fe) { /* stub not needed in this frontend */ }
+
+void timer_change_notify(long next)
+{
+    long ticks = next - GETTICKCOUNT();
+    if (ticks <= 0) ticks = 1;        /* just in case */
+    KillTimer(hwnd, TIMING_TIMER_ID);
+    SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL);
+    timing_next_time = next;
+}
+
 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                                WPARAM wParam, LPARAM lParam)
 {
@@ -1806,25 +1794,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
     switch (message) {
       case WM_TIMER:
-       if (pending_netevent)
-           enact_pending_netevent();
-       if (GetCapture() != hwnd || 
-           (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed())))
-           term_out(term);
-       noise_regular();
-       HideCaret(hwnd);
-       term_update(term);
-       ShowCaret(hwnd);
-       if (cfg.ping_interval > 0) {
-           time_t now;
-           time(&now);
-           if (now - last_movement > cfg.ping_interval) {
-               if (back)
-                   back->special(backhandle, TS_PING);
-               last_movement = now;
+       if ((UINT_PTR)wParam == TIMING_TIMER_ID) {
+           long next;
+
+           KillTimer(hwnd, TIMING_TIMER_ID);
+           if (run_timers(timing_next_time, &next)) {
+               timer_change_notify(next);
+           } else {
            }
        }
-       net_pending_errors();
        return 0;
       case WM_CREATE:
        break;
@@ -1933,7 +1911,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle));
                prev_cfg = cfg;
 
-               if (!do_reconfig(hwnd))
+               if (!do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0))
                    break;
 
                {
@@ -2304,18 +2282,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_PAINT:
        {
            PAINTSTRUCT p;
+
            HideCaret(hwnd);
            hdc = BeginPaint(hwnd, &p);
            if (pal) {
                SelectPalette(hdc, pal, TRUE);
                RealizePalette(hdc);
            }
+
            term_paint(term, hdc, 
                       (p.rcPaint.left-offset_width)/font_width,
                       (p.rcPaint.top-offset_height)/font_height,
                       (p.rcPaint.right-offset_width-1)/font_width,
                       (p.rcPaint.bottom-offset_height-1)/font_height,
-                      is_alt_pressed());
+                      TRUE);
 
            if (p.fErase ||
                p.rcPaint.left  < offset_width  ||
@@ -2326,10 +2306,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                HBRUSH fillcolour, oldbrush;
                HPEN   edge, oldpen;
                fillcolour = CreateSolidBrush (
-                                   colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]);
+                                   colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
                oldbrush = SelectObject(hdc, fillcolour);
                edge = CreatePen(PS_SOLID, 0, 
-                                   colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]);
+                                   colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
                oldpen = SelectObject(hdc, edge);
 
                /*
@@ -2351,7 +2331,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                Rectangle(hdc, p.rcPaint.left, p.rcPaint.top, 
                          p.rcPaint.right, p.rcPaint.bottom);
 
-               // SelectClipRgn(hdc, NULL);
+               /* SelectClipRgn(hdc, NULL); */
 
                SelectObject(hdc, oldbrush);
                DeleteObject(fillcolour);
@@ -2365,36 +2345,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        }
        return 0;
       case WM_NETEVENT:
-       /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc
-        * but the only one that's likely to try to overload us is FD_READ.
-        * This means buffering just one is fine.
-        */
-       if (pending_netevent)
-           enact_pending_netevent();
-
-       pending_netevent = TRUE;
-       pend_netevent_wParam = wParam;
-       pend_netevent_lParam = lParam;
-       if (WSAGETSELECTEVENT(lParam) != FD_READ)
-           enact_pending_netevent();
-
-       time(&last_movement);
+       enact_netevent(wParam, lParam);
+       net_pending_errors();
        return 0;
       case WM_SETFOCUS:
-       term->has_focus = TRUE;
+       term_set_focus(term, TRUE);
        CreateCaret(hwnd, caretbm, font_width, font_height);
        ShowCaret(hwnd);
        flash_window(0);               /* stop */
        compose_state = 0;
-       term_out(term);
        term_update(term);
        break;
       case WM_KILLFOCUS:
        show_mouseptr(1);
-       term->has_focus = FALSE;
+       term_set_focus(term, FALSE);
        DestroyCaret();
        caret_x = caret_y = -1;        /* ensure caret is replaced next time */
-       term_out(term);
        term_update(term);
        break;
       case WM_ENTERSIZEMOVE:
@@ -2965,8 +2931,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     y += offset_height;
 
     if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) {
-       attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0);
-       attr ^= ATTR_CUR_XOR;
+       attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS);
+       if (bold_mode == BOLD_COLOURS)
+           attr &= ~ATTR_BOLD;
+
+       /* cursor fg and bg */
+       attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT);
     }
 
     nfont = 0;
@@ -3024,9 +2994,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        nfont |= FONT_OEM;
 
     nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
-    nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0);
     nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
-    nbg = 2 * (nbg & 0xF) + (nbg & 0x10 ? 1 : 0);
     if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
        nfont |= FONT_BOLD;
     if (und_mode == UND_FONT && (attr & ATTR_UNDER))
@@ -3047,10 +3015,14 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        nfg = nbg;
        nbg = t;
     }
-    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD))
-       nfg |= 1;
-    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK))
-       nbg |= 1;
+    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) {
+       if (nfg < 16) nfg |= 8;
+       else if (nfg >= 256) nfg |= 1;
+    }
+    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) {
+       if (nbg < 16) nbg |= 8;
+       else if (nbg >= 256) nbg |= 1;
+    }
     fg = colours[nfg];
     bg = colours[nbg];
     SelectObject(hdc, fonts[nfont]);
@@ -3248,7 +3220,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
        pts[2].x = pts[3].x = x + char_width - 1;
        pts[0].y = pts[3].y = pts[4].y = y;
        pts[1].y = pts[2].y = y + font_height - 1;
-       oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23]));
+       oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261]));
        Polyline(hdc, pts, 5);
        oldpen = SelectObject(hdc, oldpen);
        DeleteObject(oldpen);
@@ -3273,7 +3245,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
        if (attr & TATTR_ACTCURS) {
            HPEN oldpen;
            oldpen =
-               SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23]));
+               SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261]));
            MoveToEx(hdc, startx, starty, NULL);
            LineTo(hdc, startx + dx * length, starty + dy * length);
            oldpen = SelectObject(hdc, oldpen);
@@ -3281,7 +3253,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
        } else {
            for (i = 0; i < length; i++) {
                if (i % 2 == 0) {
-                   SetPixel(hdc, startx, starty, colours[23]);
+                   SetPixel(hdc, startx, starty, colours[261]);
                }
                startx += dx;
                starty += dy;
@@ -4281,21 +4253,18 @@ static void real_palette_set(int n, int r, int g, int b)
        logpal->palPalEntry[n].peBlue = b;
        logpal->palPalEntry[n].peFlags = PC_NOCOLLAPSE;
        colours[n] = PALETTERGB(r, g, b);
-       SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry);
+       SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry);
     } else
        colours[n] = RGB(r, g, b);
 }
 
 void palette_set(void *frontend, int n, int r, int g, int b)
 {
-    static const int first[21] = {
-       0, 2, 4, 6, 8, 10, 12, 14,
-       1, 3, 5, 7, 9, 11, 13, 15,
-       16, 17, 18, 20, 22
-    };
-    real_palette_set(first[n], r, g, b);
-    if (first[n] >= 18)
-       real_palette_set(first[n] + 1, r, g, b);
+    if (n >= 16)
+       n += 256 - 16;
+    if (n > NALLCOLOURS)
+       return;
+    real_palette_set(n, r, g, b);
     if (pal) {
        HDC hdc = get_ctx(frontend);
        UnrealizeObject(pal);
@@ -4308,7 +4277,8 @@ void palette_reset(void *frontend)
 {
     int i;
 
-    for (i = 0; i < NCOLOURS; i++) {
+    /* And this */
+    for (i = 0; i < NALLCOLOURS; i++) {
        if (pal) {
            logpal->palPalEntry[i].peRed = defpal[i].rgbtRed;
            logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen;
@@ -4324,7 +4294,7 @@ void palette_reset(void *frontend)
 
     if (pal) {
        HDC hdc;
-       SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry);
+       SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry);
        hdc = get_ctx(frontend);
        RealizePalette(hdc);
        free_ctx(hdc);
@@ -4624,14 +4594,23 @@ void modalfatalbox(char *fmt, ...)
     cleanup_exit(1);
 }
 
+static void flash_window(int mode);
+static long next_flash;
+static int flashing = 0;
+
+static void flash_window_timer(void *ctx, long now)
+{
+    if (flashing && now - next_flash >= 0) {
+       flash_window(1);
+    }
+}
+
 /*
  * Manage window caption / taskbar flashing, if enabled.
  * 0 = stop, 1 = maintain, 2 = start
  */
 static void flash_window(int mode)
 {
-    static long last_flash = 0;
-    static int flashing = 0;
     if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) {
        /* stop */
        if (flashing) {
@@ -4642,20 +4621,16 @@ static void flash_window(int mode)
     } else if (mode == 2) {
        /* start */
        if (!flashing) {
-           last_flash = GetTickCount();
            flashing = 1;
            FlashWindow(hwnd, TRUE);
+           next_flash = schedule_timer(450, flash_window_timer, hwnd);
        }
 
     } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) {
        /* maintain */
        if (flashing) {
-           long now = GetTickCount();
-           long fdiff = now - last_flash;
-           if (fdiff < 0 || fdiff > 450) {
-               last_flash = now;
-               FlashWindow(hwnd, TRUE);        /* toggle */
-           }
+           FlashWindow(hwnd, TRUE);    /* toggle */
+           next_flash = schedule_timer(450, flash_window_timer, hwnd);
        }
     }
 }