~ubuntu-branches/ubuntu/oneiric/mozc/oneiric

« back to all changes in this revision

Viewing changes to gui/base/win_util.cc

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2010-07-14 03:26:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100714032647-13qjisj6m8cm8jdx
Tags: 0.12.410.102-1
* New upstream release (Closes: #588971).
  - Add mozc-server, mozc-utils-gui and scim-mozc packages.
* Update debian/rules.
  Add --gypdir option to build_mozc.py.
* Update debian/control.
  - Bumped standards-version to 3.9.0.
  - Update description.
* Add mozc icon (Closes: #588972).
* Add patch which revises issue 18.
  ibus_mozc_issue18.patch
* kFreeBSD build support.
  support_kfreebsd.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2010, Google Inc.
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are
 
6
// met:
 
7
//
 
8
//     * Redistributions of source code must retain the above copyright
 
9
// notice, this list of conditions and the following disclaimer.
 
10
//     * Redistributions in binary form must reproduce the above
 
11
// copyright notice, this list of conditions and the following disclaimer
 
12
// in the documentation and/or other materials provided with the
 
13
// distribution.
 
14
//     * Neither the name of Google Inc. nor the names of its
 
15
// contributors may be used to endorse or promote products derived from
 
16
// this software without specific prior written permission.
 
17
//
 
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 
 
30
#include "gui/base/win_util.h"
 
31
 
 
32
#include <QtCore/QFile>
 
33
#include <QtCore/QLibrary>
 
34
#include <QtCore/QList>
 
35
#include <QtCore/QPointer>
 
36
#include <QtGui/QApplication>
 
37
#include <QtGui/QDesktopWidget>
 
38
#include <QtGui/QPainter>
 
39
#include <QtGui/QPaintEngine>
 
40
#include <QtGui/QWidget>
 
41
 
 
42
#include "base/base.h"
 
43
#include "base/util.h"
 
44
#include "base/singleton.h"
 
45
 
 
46
#ifdef OS_WINDOWS
 
47
#include <dwmapi.h>
 
48
#include <tmschema.h>
 
49
#include <uxtheme.h>
 
50
#include <windows.h>
 
51
#include <winuser.h>
 
52
#include <Qt/qt_windows.h>
 
53
 
 
54
#ifndef WM_DWMCOMPOSITIONCHANGED
 
55
#define WM_DWMCOMPOSITIONCHANGED        0x031E
 
56
#endif  // WM_DWMCOMPOSITIONCHANGED
 
57
 
 
58
// DWM API
 
59
typedef HRESULT (WINAPI *FPDwmIsCompositionEnabled)
 
60
    (BOOL *pfEnabled);
 
61
typedef HRESULT (WINAPI *FPDwmExtendFrameIntoClientArea)
 
62
    (HWND hWnd,
 
63
     const MARGINS *pMarInset);
 
64
typedef HRESULT (WINAPI *FPDwmEnableBlurBehindWindow)
 
65
    (HWND hWnd,
 
66
     const DWM_BLURBEHIND *pBlurBehind);
 
67
 
 
68
// Theme API
 
69
typedef HANDLE (WINAPI *FPOpenThemeData)
 
70
    (HWND hwnd, LPCWSTR pszClassList);
 
71
typedef HRESULT (WINAPI *FPCloseThemeData)
 
72
    (HANDLE hTheme);
 
73
typedef HRESULT (WINAPI *FPDrawThemeTextEx)
 
74
    (HANDLE hTheme, HDC hdc, int iPartId, int iStateId,
 
75
     LPCWSTR pszText, int cchText, DWORD dwTextFlags,
 
76
     LPRECT pRect, const DTTOPTS *pOptions);
 
77
typedef HRESULT (WINAPI *FPGetThemeSysFont)
 
78
    (HANDLE hTheme, int iFontId, LOGFONTW *plf);
 
79
 
 
80
#endif  // OS_WINDOWS
 
81
 
 
82
namespace mozc {
 
83
namespace gui {
 
84
 
 
85
#ifdef OS_WINDOWS
 
86
namespace {
 
87
 
 
88
FPDwmIsCompositionEnabled      gDwmIsCompositionEnabled      = NULL;
 
89
FPDwmEnableBlurBehindWindow    gDwmEnableBlurBehindWindow    = NULL;
 
90
FPDwmExtendFrameIntoClientArea gDwmExtendFrameIntoClientArea = NULL;
 
91
FPOpenThemeData                gOpenThemeData                = NULL;
 
92
FPCloseThemeData               gCloseThemeData               = NULL;
 
93
FPDrawThemeTextEx              gDrawThemeTextEx              = NULL;
 
94
FPGetThemeSysFont              gGetThemeSysFont              = NULL;
 
95
 
 
96
class WindowNotifier : public QWidget {
 
97
 public:
 
98
  WindowNotifier() {
 
99
    winId();   // to make a window handle
 
100
  }
 
101
 
 
102
  virtual ~WindowNotifier() {}
 
103
 
 
104
  void AddWidget(QWidget *widget) {
 
105
    widgets_.append(widget);
 
106
  }
 
107
 
 
108
  void RemoveWidget(QWidget *widget) {
 
109
    widgets_.removeAll(widget);
 
110
  }
 
111
 
 
112
  bool winEvent(MSG *message, long *result);
 
113
 
 
114
  void InstallStyleSheets(const QString &dwm_on_style,
 
115
                          const QString &dwm_off_style) {
 
116
    dwm_on_style_ = dwm_on_style;
 
117
    dwm_off_style_ = dwm_off_style;
 
118
  }
 
119
 
 
120
  static WindowNotifier *Get() {
 
121
    return Singleton<WindowNotifier>::get();
 
122
  }
 
123
 
 
124
 private:
 
125
  QWidgetList widgets_;
 
126
  QString dwm_on_style_;
 
127
  QString dwm_off_style_;
 
128
};
 
129
 
 
130
class DwmResolver {
 
131
 public:
 
132
  DwmResolver() : dwmlib_(NULL), themelib_(NULL) {
 
133
    dwmlib_ = Util::LoadSystemLibrary(L"dwmapi.dll");
 
134
    themelib_ = Util::LoadSystemLibrary(L"uxtheme.dll");
 
135
 
 
136
    if (NULL != dwmlib_) {
 
137
      gDwmIsCompositionEnabled =
 
138
          reinterpret_cast<FPDwmIsCompositionEnabled>
 
139
          (::GetProcAddress(dwmlib_,
 
140
                            "DwmIsCompositionEnabled"));
 
141
      gDwmExtendFrameIntoClientArea =
 
142
          reinterpret_cast<FPDwmExtendFrameIntoClientArea>
 
143
          (::GetProcAddress(dwmlib_,
 
144
                            "DwmExtendFrameIntoClientArea"));
 
145
      gDwmEnableBlurBehindWindow =
 
146
          reinterpret_cast<FPDwmEnableBlurBehindWindow>
 
147
          (::GetProcAddress(dwmlib_,
 
148
                            "DwmEnableBlurBehindWindow"));
 
149
    }
 
150
 
 
151
    if (NULL != themelib_) {
 
152
      gOpenThemeData =
 
153
          reinterpret_cast<FPOpenThemeData>(
 
154
              ::GetProcAddress(themelib_, "OpenThemeData"));
 
155
      gCloseThemeData =
 
156
          reinterpret_cast<FPCloseThemeData>(
 
157
              ::GetProcAddress(themelib_, "CloseThemeData"));
 
158
      gDrawThemeTextEx =
 
159
          reinterpret_cast<FPDrawThemeTextEx>(
 
160
              ::GetProcAddress(themelib_, "DrawThemeTextEx"));
 
161
      gGetThemeSysFont =
 
162
          reinterpret_cast<FPGetThemeSysFont>(
 
163
              ::GetProcAddress(themelib_, "GetThemeSysFont"));
 
164
    }
 
165
  }
 
166
 
 
167
  bool IsAvailable() const {
 
168
    return (gDwmIsCompositionEnabled != NULL &&
 
169
            gDwmExtendFrameIntoClientArea != NULL &&
 
170
            gDwmEnableBlurBehindWindow != NULL &&
 
171
            gOpenThemeData != NULL &&
 
172
            gCloseThemeData != NULL &&
 
173
            gDrawThemeTextEx != NULL &&
 
174
            gGetThemeSysFont != NULL);
 
175
  }
 
176
 
 
177
  static bool ResolveLibs() {
 
178
    return Singleton<DwmResolver>::get()->IsAvailable();
 
179
  }
 
180
 
 
181
 private:
 
182
  HMODULE dwmlib_;
 
183
  HMODULE themelib_;
 
184
};
 
185
}  //namespace
 
186
#endif  // OS_WINDOWS
 
187
 
 
188
bool WinUtil::IsCompositionEnabled() {
 
189
#ifdef OS_WINDOWS
 
190
  if (!DwmResolver::ResolveLibs()) {
 
191
    return false;
 
192
  }
 
193
 
 
194
  HRESULT hr = S_OK;
 
195
  BOOL is_enabled = false;
 
196
  hr = gDwmIsCompositionEnabled(&is_enabled);
 
197
  if (SUCCEEDED(hr)) {
 
198
    return is_enabled;
 
199
  } else {
 
200
    LOG(ERROR) << "DwmIsCompositionEnabled() failed: "
 
201
               << static_cast<long>(hr);
 
202
  }
 
203
#endif  // OS_WINDOWS
 
204
 
 
205
  return false;
 
206
}
 
207
 
 
208
bool WinUtil::ExtendFrameIntoClientArea(QWidget *widget,
 
209
                                        int left, int top,
 
210
                                        int right, int bottom) {
 
211
  DCHECK(widget);
 
212
 
 
213
#ifdef OS_WINDOWS
 
214
  if (!DwmResolver::ResolveLibs()) {
 
215
    return false;
 
216
  }
 
217
 
 
218
  HRESULT hr = S_OK;
 
219
  MARGINS margin = { left, top, right, bottom };
 
220
  hr = gDwmExtendFrameIntoClientArea(widget->winId(), &margin);
 
221
  if (SUCCEEDED(hr)) {
 
222
    WindowNotifier::Get()->AddWidget(widget);
 
223
    widget->setAttribute(Qt::WA_TranslucentBackground, true);
 
224
    return true;
 
225
  } else {
 
226
    LOG(ERROR) << "DwmExtendFrameIntoClientArea() failed: "
 
227
               << static_cast<long>(hr);
 
228
  }
 
229
#endif  // OS_WINDOWS
 
230
 
 
231
  return false;
 
232
}
 
233
 
 
234
#ifdef OS_WINDOWS
 
235
bool WindowNotifier::winEvent(MSG *message, long *result) {
 
236
  if (message != NULL && message->message == WM_DWMCOMPOSITIONCHANGED) {
 
237
    const bool composition_enabled = WinUtil::IsCompositionEnabled();
 
238
 
 
239
    // switch styles if need be
 
240
    if (!dwm_on_style_.isEmpty() && !dwm_off_style_.isEmpty()) {
 
241
      if (composition_enabled) {
 
242
        qApp->setStyleSheet(dwm_on_style_);
 
243
      } else {
 
244
        qApp->setStyleSheet(dwm_off_style_);
 
245
      }
 
246
    }
 
247
 
 
248
    foreach(QWidget *widget, widgets_) {
 
249
      if (widget != NULL) {
 
250
        widget->setAttribute(Qt::WA_NoSystemBackground,
 
251
                             composition_enabled);
 
252
        // TODO(taku): left/top/right/bottom are not updated.
 
253
        // need to be fixed.
 
254
        if (composition_enabled) {
 
255
          MARGINS margin = { -1, 0, 0, 0 };
 
256
          gDwmExtendFrameIntoClientArea(widget->winId(), &margin);
 
257
          widget->setAttribute(Qt::WA_TranslucentBackground, true);
 
258
        }
 
259
        widget->update();
 
260
      }
 
261
    }
 
262
  }
 
263
 
 
264
  // call default
 
265
  return QWidget::winEvent(message, result);
 
266
}
 
267
#endif  // OS_WINDOWS
 
268
 
 
269
QRect WinUtil::GetTextRect(QWidget *widget, const QString &text) {
 
270
  DCHECK(widget);
 
271
  const QFont font = QApplication::font(widget);
 
272
  const QFontMetrics fontMetrics(font);
 
273
  return fontMetrics.boundingRect(text);
 
274
}
 
275
 
 
276
void WinUtil::InstallStyleSheets(const QString &dwm_on_style,
 
277
                                 const QString &dwm_off_style) {
 
278
#ifdef OS_WINDOWS
 
279
  WindowNotifier::Get()->InstallStyleSheets(dwm_on_style,
 
280
                                            dwm_off_style);
 
281
#endif  // OS_WINDOWS
 
282
}
 
283
 
 
284
void WinUtil::InstallStyleSheetsFiles(const QString &dwm_on_style_file,
 
285
                                      const QString &dwm_off_style_file) {
 
286
#ifdef OS_WINDOWS
 
287
  QFile file1(dwm_on_style_file);
 
288
  file1.open(QFile::ReadOnly);
 
289
  QFile file2(dwm_off_style_file);
 
290
  file2.open(QFile::ReadOnly);
 
291
  WinUtil::InstallStyleSheets(QLatin1String(file1.readAll()),
 
292
                              QLatin1String(file2.readAll()));
 
293
#endif  // OS_WINDOWS
 
294
}
 
295
 
 
296
void WinUtil::DrawThemeText(const QString &text,
 
297
                            const QRect &rect,
 
298
                            int glow_size,
 
299
                            QPainter *painter) {
 
300
  DCHECK(painter);
 
301
 
 
302
#ifdef OS_WINDOWS
 
303
  if (!DwmResolver::ResolveLibs()) {
 
304
    return;
 
305
  }
 
306
 
 
307
  HDC hdc = painter->paintEngine()->getDC();
 
308
  if (NULL == hdc) {
 
309
    LOG(ERROR) << "hdc is NULL";
 
310
    return;
 
311
  }
 
312
 
 
313
  HANDLE theme = gOpenThemeData(qApp->desktop()->winId(), L"WINDOW");
 
314
  if (theme == NULL) {
 
315
    LOG(ERROR) << "::OpenThemaData() failed";
 
316
    return;
 
317
  }
 
318
 
 
319
  // Set up a memory DC and bitmap that we'll draw into
 
320
  HDC dc_mem = ::CreateCompatibleDC(hdc);
 
321
  if (dc_mem == NULL) {
 
322
    gCloseThemeData(theme);
 
323
    LOG(ERROR) << "::CreateCompatibleDC() failed: " << ::GetLastError();
 
324
    return;
 
325
  }
 
326
 
 
327
  BITMAPINFO dib = { 0 };
 
328
  dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 
329
  dib.bmiHeader.biWidth = rect.width();
 
330
  dib.bmiHeader.biHeight = -rect.height();
 
331
  dib.bmiHeader.biPlanes = 1;
 
332
  dib.bmiHeader.biBitCount = 32;
 
333
  dib.bmiHeader.biCompression = BI_RGB;
 
334
 
 
335
  HBITMAP bmp = ::CreateDIBSection(hdc, &dib,
 
336
                                   DIB_RGB_COLORS, NULL, NULL, 0);
 
337
  if (NULL == bmp) {
 
338
    ::DeleteDC(dc_mem);
 
339
    gCloseThemeData(theme);
 
340
    LOG(ERROR) << "::CreateDIBSection() failed: " << ::GetLastError();
 
341
    return;
 
342
  }
 
343
 
 
344
  LOGFONT lf = { 0 };
 
345
  if (NULL != theme) {
 
346
    gGetThemeSysFont(theme, TMT_CAPTIONFONT, &lf);
 
347
  } else {
 
348
    NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };
 
349
    ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
 
350
                           sizeof(NONCLIENTMETRICS), &ncm, false);
 
351
    lf = ncm.lfMessageFont;
 
352
  }
 
353
 
 
354
  HFONT caption_font = ::CreateFontIndirect(&lf);
 
355
  HBITMAP old_bmp = reinterpret_cast<HBITMAP>(
 
356
      ::SelectObject(dc_mem,
 
357
                     reinterpret_cast<HGDIOBJ>(bmp)));
 
358
  HFONT old_font = reinterpret_cast<HFONT>(
 
359
      ::SelectObject(dc_mem,
 
360
                     reinterpret_cast<HGDIOBJ>(caption_font)));
 
361
 
 
362
  DTTOPTS dto = { sizeof(DTTOPTS) };
 
363
  const UINT format = DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX;
 
364
  RECT rctext ={ 0, 0, rect.width(), rect.height() };
 
365
 
 
366
  dto.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE;
 
367
  dto.iGlowSize = glow_size;
 
368
 
 
369
  const HRESULT hr =
 
370
      gDrawThemeTextEx(theme, dc_mem, 0, 0,
 
371
                       reinterpret_cast<LPCWSTR>(text.utf16()),
 
372
                       -1, format, &rctext, &dto);
 
373
  if (SUCCEEDED(hr)) {
 
374
    // Copy to the painter's HDC
 
375
    if (!::BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(),
 
376
                  dc_mem, 0, 0, SRCCOPY)) {
 
377
      LOG(ERROR) << "::BitBlt() failed: " << ::GetLastError();
 
378
    }
 
379
  } else {
 
380
    LOG(ERROR) << "::DrawThemeTextEx() failed: " << static_cast<long>(hr);
 
381
  }
 
382
 
 
383
  ::SelectObject(dc_mem, reinterpret_cast<HGDIOBJ>(old_bmp));
 
384
  ::SelectObject(dc_mem, reinterpret_cast<HGDIOBJ>(old_font));
 
385
  ::DeleteObject(bmp);
 
386
  ::DeleteObject(caption_font);
 
387
  ::DeleteDC(dc_mem);
 
388
  gCloseThemeData(theme);
 
389
 
 
390
#endif  // OS_WINDOWS
 
391
}
 
392
 
 
393
#ifdef OS_WINDOWS
 
394
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lp) {
 
395
  DWORD id = 0;
 
396
  ::GetWindowThreadProcessId(hwnd, &id);
 
397
  if (static_cast<uint32>(id) != static_cast<uint32>(lp)) {
 
398
    // continue enum
 
399
    return TRUE;
 
400
  }
 
401
  if (::SetForegroundWindow(hwnd) == 0) {
 
402
    LOG(ERROR) << "::SetFOregroundWindow() failed";
 
403
  }
 
404
  return FALSE;
 
405
}
 
406
#endif  // OS_WINDOWS
 
407
 
 
408
void WinUtil::ActivateWindow(uint32 process_id) {
 
409
#ifdef OS_WINDOWS
 
410
  if (::EnumWindows(EnumWindowsProc, static_cast<LPARAM>(process_id)) != 0) {
 
411
    LOG(ERROR) << "could not find the exsisting window.";
 
412
  }
 
413
#endif  // OS_WINDOWS
 
414
}
 
415
}  // namespace gui
 
416
}  // namespace mozc