1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
18 #include "progressui.h"
19 #include "readstrings.h"
23 #define TIMER_INTERVAL 100
25 #define RESIZE_WINDOW(hwnd, extrax, extray) \
28 GetWindowRect(hwnd, &windowSize); \
29 SetWindowPos(hwnd, 0, 0, 0, windowSize.right - windowSize.left + extrax, \
30 windowSize.bottom - windowSize.top + extray, \
31 SWP_NOMOVE | SWP_NOZORDER); \
34 #define MOVE_WINDOW(hwnd, dx, dy) \
38 GetWindowRect(hwnd, &rc); \
41 ScreenToClient(GetParent(hwnd), &pt); \
42 SetWindowPos(hwnd, 0, pt.x + dx, pt.y + dy, 0, 0, \
43 SWP_NOSIZE | SWP_NOZORDER); \
46 static float sProgress
; // between 0 and 100
47 static BOOL sQuit
= FALSE
;
48 static BOOL sIndeterminate
= FALSE
;
49 static StringTable sUIStrings
;
52 GetStringsFile(WCHAR filename
[MAX_PATH
])
54 if (!GetModuleFileNameW(nullptr, filename
, MAX_PATH
))
57 WCHAR
*dot
= wcsrchr(filename
, '.');
58 if (!dot
|| wcsicmp(dot
+ 1, L
"exe"))
61 wcscpy(dot
+ 1, L
"ini");
66 UpdateDialog(HWND hDlg
)
68 int pos
= int(sProgress
+ 0.5f
);
69 HWND hWndPro
= GetDlgItem(hDlg
, IDC_PROGRESS
);
70 SendMessage(hWndPro
, PBM_SETPOS
, pos
, 0L);
73 // The code in this function is from MSDN:
74 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp
76 CenterDialog(HWND hDlg
)
78 RECT rc
, rcOwner
, rcDlg
;
80 // Get the owner window and dialog box rectangles.
81 HWND desktop
= GetDesktopWindow();
83 GetWindowRect(desktop
, &rcOwner
);
84 GetWindowRect(hDlg
, &rcDlg
);
85 CopyRect(&rc
, &rcOwner
);
87 // Offset the owner and dialog box rectangles so that
88 // right and bottom values represent the width and
89 // height, and then offset the owner again to discard
90 // space taken up by the dialog box.
92 OffsetRect(&rcDlg
, -rcDlg
.left
, -rcDlg
.top
);
93 OffsetRect(&rc
, -rc
.left
, -rc
.top
);
94 OffsetRect(&rc
, -rcDlg
.right
, -rcDlg
.bottom
);
96 // The new position is the sum of half the remaining
97 // space and the owner's original position.
101 rcOwner
.left
+ (rc
.right
/ 2),
102 rcOwner
.top
+ (rc
.bottom
/ 2),
103 0, 0, // ignores size arguments
108 InitDialog(HWND hDlg
)
110 WCHAR szwTitle
[MAX_TEXT_LEN
];
111 WCHAR szwInfo
[MAX_TEXT_LEN
];
113 MultiByteToWideChar(CP_UTF8
, 0, sUIStrings
.title
, -1, szwTitle
,
114 sizeof(szwTitle
)/sizeof(szwTitle
[0]));
115 MultiByteToWideChar(CP_UTF8
, 0, sUIStrings
.info
, -1, szwInfo
,
116 sizeof(szwInfo
)/sizeof(szwInfo
[0]));
118 SetWindowTextW(hDlg
, szwTitle
);
119 SetWindowTextW(GetDlgItem(hDlg
, IDC_INFO
), szwInfo
);
122 HICON hIcon
= LoadIcon(GetModuleHandle(nullptr),
123 MAKEINTRESOURCE(IDI_DIALOG
));
125 SendMessage(hDlg
, WM_SETICON
, ICON_BIG
, (LPARAM
) hIcon
);
127 HWND hWndPro
= GetDlgItem(hDlg
, IDC_PROGRESS
);
128 SendMessage(hWndPro
, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
131 LONG_PTR val
= GetWindowLongPtr(hWndPro
, GWL_STYLE
);
132 SetWindowLongPtr(hWndPro
, GWL_STYLE
, val
|PBS_MARQUEE
);
133 SendMessage(hWndPro
,(UINT
) PBM_SETMARQUEE
,(WPARAM
) TRUE
,(LPARAM
)50 );
136 // Resize the dialog to fit all of the text if necessary.
137 RECT infoSize
, textSize
;
138 HWND hWndInfo
= GetDlgItem(hDlg
, IDC_INFO
);
140 // Get the control's font for calculating the new size for the control
141 HDC hDCInfo
= GetDC(hWndInfo
);
144 hInfoFont
= (HFONT
)SendMessage(hWndInfo
, WM_GETFONT
, 0, 0);
147 hOldFont
= (HFONT
)SelectObject(hDCInfo
, hInfoFont
);
149 // Measure the space needed for the text on a single line. DT_CALCRECT means
151 if (DrawText(hDCInfo
, szwInfo
, -1, &textSize
,
152 DT_CALCRECT
| DT_NOCLIP
| DT_SINGLELINE
))
154 GetClientRect(hWndInfo
, &infoSize
);
156 // Calculate the additional space needed for the text by subtracting from
157 // the rectangle returned by DrawText the existing client rectangle's width
159 extra
.cx
= (textSize
.right
- textSize
.left
) - \
160 (infoSize
.right
- infoSize
.left
);
161 extra
.cy
= (textSize
.bottom
- textSize
.top
) - \
162 (infoSize
.bottom
- infoSize
.top
);
167 if ((extra
.cx
> 0) || (extra
.cy
> 0))
169 RESIZE_WINDOW(hDlg
, extra
.cx
, extra
.cy
);
170 RESIZE_WINDOW(hWndInfo
, extra
.cx
, extra
.cy
);
171 RESIZE_WINDOW(hWndPro
, extra
.cx
, 0);
172 MOVE_WINDOW(hWndPro
, 0, extra
.cy
);
177 SelectObject(hDCInfo
, hOldFont
);
179 ReleaseDC(hWndInfo
, hDCInfo
);
181 CenterDialog(hDlg
); // make dialog appear in the center of the screen
183 SetTimer(hDlg
, TIMER_ID
, TIMER_INTERVAL
, nullptr);
186 // Message handler for update dialog.
187 static LRESULT CALLBACK
188 DialogProc(HWND hDlg
, UINT message
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
214 InitProgressUI(int* /*argc*/, WCHAR
*** /*argv*/)
220 * Initializes the progress UI strings
222 * @return 0 on success, -1 on error
225 InitProgressUIStrings()
227 // If we do not have updater.ini, then we should not bother showing UI.
228 WCHAR filename
[MAX_PATH
];
229 if (!GetStringsFile(filename
))
231 strcpy(sUIStrings
.title
, "LibreOffice Update");
232 strcpy(sUIStrings
.info
, "Please wait while we update your installation.");
236 if (_waccess(filename
, 04))
238 strcpy(sUIStrings
.title
, "LibreOffice Update");
239 strcpy(sUIStrings
.info
, "Please wait while we update your installation.");
243 // If the updater.ini doesn't have the required strings, then we should not
244 // bother showing UI.
245 if (ReadStrings(filename
, &sUIStrings
) != OK
)
247 strcpy(sUIStrings
.title
, "LibreOffice Update");
248 strcpy(sUIStrings
.info
, "Please wait while we update your installation.");
255 ShowProgressUI(bool indeterminate
, bool initUIStrings
)
257 sIndeterminate
= indeterminate
;
260 // Only show the Progress UI if the process is taking a significant amount of
261 // time where a significant amount of time is defined as .5 seconds after
262 // ShowProgressUI is called sProgress is less than 70.
265 if (sQuit
|| sProgress
> 70.0f
)
269 // Don't load the UI if there's an <exe_name>.Local directory for redirection.
270 WCHAR appPath
[MAX_PATH
+ 1] = { L
'\0' };
271 if (!GetModuleFileNameW(nullptr, appPath
, MAX_PATH
))
276 if (wcslen(appPath
) + wcslen(L
".Local") >= MAX_PATH
)
281 wcscat(appPath
, L
".Local");
283 if (!_waccess(appPath
, 04))
288 // Don't load the UI if the strings for the UI are not provided.
289 if (initUIStrings
&& InitProgressUIStrings() == -1)
294 if (!GetModuleFileNameW(nullptr, appPath
, MAX_PATH
))
299 // Use an activation context that supports visual styles for the controls.
301 actx
.cbSize
= sizeof(ACTCTXW
);
302 actx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
303 actx
.hModule
= GetModuleHandle(NULL
); // Use the embedded manifest
304 // This is needed only for Win XP but doesn't cause a problem with other
305 // versions of Windows.
306 actx
.lpSource
= appPath
;
307 actx
.lpResourceName
= MAKEINTRESOURCE(IDR_COMCTL32_MANIFEST
);
309 HANDLE hactx
= CreateActCtxW(&actx
);
310 ULONG_PTR actxCookie
= NULL
;
311 if (hactx
!= INVALID_HANDLE_VALUE
)
313 // Push the specified activation context to the top of the activation stack.
314 ActivateActCtx(hactx
, &actxCookie
);
317 INITCOMMONCONTROLSEX icc
=
319 sizeof(INITCOMMONCONTROLSEX
),
322 InitCommonControlsEx(&icc
);
324 DialogBox(GetModuleHandle(nullptr),
325 MAKEINTRESOURCE(IDD_DIALOG
), nullptr,
326 (DLGPROC
) DialogProc
);
328 if (hactx
!= INVALID_HANDLE_VALUE
)
330 // Deactivate the context now that the comctl32.dll is loaded.
331 DeactivateActCtx(0, actxCookie
);
344 UpdateProgressUI(float progress
)
346 sProgress
= progress
; // 32-bit writes are atomic