Back to index

lightning-sunbird  0.9+nobinonly
progressui_win.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is Google Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Darin Fisher <darin@meer.net>
00024  *  Masayuki Nakano <masayuki@d-toybox.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <stdio.h>
00041 #include <windows.h>
00042 #include <commctrl.h>
00043 #include <process.h>
00044 #include <io.h>
00045 #include "resource.h"
00046 
00047 #define TIMER_ID 1
00048 #define TIMER_INTERVAL 100
00049 
00050 #define MAX_INFO_LENGTH 512
00051 
00052 #define RESIZE_WINDOW(hwnd, extrax, extray) \
00053   { \
00054     RECT windowSize; \
00055     GetWindowRect(hwnd, &windowSize); \
00056     SetWindowPos(hwnd, 0, 0, 0, windowSize.right - windowSize.left + extrax, \
00057                  windowSize.bottom - windowSize.top + extray, \
00058                  SWP_NOMOVE | SWP_NOZORDER); \
00059   }
00060 
00061 #define MOVE_WINDOW(hwnd, dx, dy) \
00062   { \
00063     WINDOWPLACEMENT windowPos; \
00064     windowPos.length = sizeof(windowPos); \
00065     GetWindowPlacement(hwnd, &windowPos); \
00066     SetWindowPos(hwnd, 0, windowPos.rcNormalPosition.left + dx, windowPos.rcNormalPosition.top + dy, 0, 0, \
00067                  SWP_NOSIZE | SWP_NOZORDER); \
00068   }
00069 
00070 static float sProgress;  // between 0 and 100
00071 static BOOL  sQuit = FALSE;
00072 static HFONT sSystemFont = 0;
00073 
00074 static BOOL
00075 GetStringsFile(char filename[MAX_PATH])
00076 {
00077   if (!GetModuleFileName(NULL, filename, MAX_PATH))
00078     return FALSE;
00079 
00080   char *dot = strrchr(filename, '.');
00081   if (!dot || stricmp(dot + 1, "exe"))
00082     return FALSE;
00083 
00084   strcpy(dot + 1, "ini");
00085   return TRUE;
00086 }
00087 
00088 static void
00089 UpdateDialog(HWND hDlg)
00090 {
00091   int pos = int(sProgress + 0.5f);
00092   SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETPOS, pos, 0L);
00093 }
00094 
00095 static void
00096 ResizeDialogToFit(HWND hDlg)
00097 {
00098   char text[MAX_INFO_LENGTH];
00099   RECT infoSize, textSize;
00100   HFONT hInfoFont, hOldFont;
00101 
00102   HWND hWndInfo = GetDlgItem(hDlg, IDC_INFO);
00103   HWND hWndPro  = GetDlgItem(hDlg, IDC_PROGRESS);
00104 
00105   // Get the text that is displayed - this is what we're going to make fit.
00106   if (!GetWindowText(hWndInfo, text, sizeof(text)))
00107     return;
00108 
00109   // We need the current size and font to calculate the adjustment.
00110   GetClientRect(hWndInfo, &infoSize);
00111   HDC hDCInfo = GetDC(hWndInfo);
00112   hInfoFont = (HFONT)SendMessage(hWndInfo, WM_GETFONT, 0, 0);
00113   if (hInfoFont)
00114     hOldFont = (HFONT)SelectObject(hDCInfo, hInfoFont);
00115 
00116   // Measure the space needed for the text - DT_CALCRECT means nothing is drawn.
00117   if (DrawText(hDCInfo, text, -1, &textSize,
00118                DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE)) {
00119     SIZE extra;
00120     extra.cx = (textSize.right - textSize.left) - (infoSize.right - infoSize.left);
00121     extra.cy = (textSize.bottom - textSize.top) - (infoSize.bottom - infoSize.top);
00122     if (extra.cx < 0)
00123       extra.cx = 0;
00124     if (extra.cy < 0)
00125       extra.cy = 0;
00126 
00127     if ((extra.cx > 0) || (extra.cy > 0)) {
00128       RESIZE_WINDOW(hDlg, extra.cx, extra.cy);
00129       RESIZE_WINDOW(hWndInfo, extra.cx, extra.cy);
00130       RESIZE_WINDOW(hWndPro, extra.cx, 0);
00131       MOVE_WINDOW(hWndPro, 0, extra.cy);
00132     }
00133   }
00134 
00135   if (hOldFont)
00136     SelectObject(hDCInfo, hOldFont);
00137 
00138   ReleaseDC(hWndInfo, hDCInfo);
00139 }
00140 
00141 // The code in this function is from MSDN:
00142 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp
00143 static void
00144 CenterDialog(HWND hDlg)
00145 {
00146   RECT rc, rcOwner, rcDlg;
00147 
00148   // Get the owner window and dialog box rectangles. 
00149   HWND desktop = GetDesktopWindow();
00150 
00151   GetWindowRect(desktop, &rcOwner); 
00152   GetWindowRect(hDlg, &rcDlg); 
00153   CopyRect(&rc, &rcOwner); 
00154 
00155   // Offset the owner and dialog box rectangles so that 
00156   // right and bottom values represent the width and 
00157   // height, and then offset the owner again to discard 
00158   // space taken up by the dialog box. 
00159 
00160   OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); 
00161   OffsetRect(&rc, -rc.left, -rc.top); 
00162   OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); 
00163 
00164   // The new position is the sum of half the remaining 
00165   // space and the owner's original position. 
00166 
00167   SetWindowPos(hDlg, 
00168                HWND_TOP, 
00169                rcOwner.left + (rc.right / 2), 
00170                rcOwner.top + (rc.bottom / 2), 
00171                0, 0,          // ignores size arguments 
00172                SWP_NOSIZE); 
00173 }
00174 
00175 static void
00176 SetItemText(HWND hwnd, const char *key, const char *ini)
00177 {
00178   char text[MAX_INFO_LENGTH];
00179   if (!GetPrivateProfileString("Strings", key, NULL, text, sizeof(text), ini))
00180     return;
00181   SetWindowText(hwnd, text);
00182 }
00183 
00184 static void
00185 InitDialog(HWND hDlg)
00186 {
00187   char filename[MAX_PATH];
00188   if (!GetStringsFile(filename))
00189     return;
00190 
00191   SetItemText(hDlg, "Title", filename);
00192   SetItemText(GetDlgItem(hDlg, IDC_INFO), "Info", filename);
00193 
00194   // On Win9x, we need to send WM_SETFONT for l10n builds.  Yes, we shouldn't
00195   // use the system font.  For example, if the text has Japanese characters on
00196   // Win98-en, then the text may not be displayed correctly.  We should perhaps
00197   // support loading a font named in updater.ini; however, even then there are
00198   // cases where it might not work properly.
00199   if (!sSystemFont) {
00200     NONCLIENTMETRICS ncm;
00201     memset(&ncm, 0, sizeof(ncm));
00202     ncm.cbSize = sizeof(ncm);
00203     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
00204     sSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
00205   }
00206   if (sSystemFont)
00207     SendDlgItemMessage(hDlg, IDC_INFO, WM_SETFONT, (WPARAM)sSystemFont, 0L);
00208 
00209   // Set dialog icon
00210   HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_DIALOG));
00211   if (hIcon)
00212     SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
00213 
00214   SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
00215 
00216   // Resize dialog to fit all the text.
00217   ResizeDialogToFit(hDlg);
00218 
00219   CenterDialog(hDlg);  // make dialog appear in the center of the screen
00220 
00221   SetTimer(hDlg, TIMER_ID, TIMER_INTERVAL, NULL);
00222 }
00223 
00224 // Message handler for about box.
00225 static LRESULT CALLBACK
00226 DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
00227 {
00228   switch (message)
00229   {
00230   case WM_INITDIALOG:
00231     InitDialog(hDlg);
00232     return TRUE;
00233 
00234   case WM_TIMER:
00235     if (sQuit) {
00236       EndDialog(hDlg, 0);
00237       if (sSystemFont) {
00238         DeleteObject(sSystemFont);
00239         sSystemFont = 0;
00240       }
00241     } else {
00242       UpdateDialog(hDlg);
00243     }
00244     return TRUE;
00245 
00246   case WM_COMMAND:
00247     return TRUE;
00248   }
00249   return FALSE;
00250 }
00251 
00252 int
00253 InitProgressUI(int *argc, char ***argv)
00254 {
00255   return 0;
00256 }
00257 
00258 int
00259 ShowProgressUI()
00260 {
00261   // Only show the Progress UI if the process is taking significant time.
00262   // Here we measure significant time as taking more than one second.
00263 
00264   Sleep(500);
00265 
00266   if (sQuit || sProgress > 50.0f)
00267     return 0;
00268 
00269   // If we do not have updater.ini, then we should not bother showing UI.
00270   char filename[MAX_PATH];
00271   if (!GetStringsFile(filename))
00272     return -1;
00273   if (_access(filename, 04))
00274     return -1;
00275 
00276   INITCOMMONCONTROLSEX icc = {
00277     sizeof(INITCOMMONCONTROLSEX),
00278     ICC_PROGRESS_CLASS
00279   };
00280   InitCommonControlsEx(&icc);
00281 
00282   DialogBox(GetModuleHandle(NULL),
00283             MAKEINTRESOURCE(IDD_DIALOG), NULL,
00284             (DLGPROC) DialogProc);
00285 
00286   return 0;
00287 }
00288 
00289 void
00290 QuitProgressUI()
00291 {
00292   sQuit = TRUE;
00293 }
00294 
00295 void
00296 UpdateProgressUI(float progress)
00297 {
00298   sProgress = progress;  // 32-bit writes are atomic
00299 }