Remove legacy code from W32Compat

frontend/gtkmm/src/win32/DesktopWindow.cc
frontend/gtkmm/src/win32/W32Compat.cc
frontend/gtkmm/src/win32/W32Compat.hh

- Remove legacy code
The W32Compat class was written eight years ago when Win 9x
compatibility was still an issue. Many of the Win2k+ functions had to
be acquired dynamically, and that's no longer necessary.
New W32ForceFocus class to force window focus

build/cmake/frontend/CMakeLists.txt
frontend/gtkmm/src/BreakWindow.cc
frontend/gtkmm/src/BreakWindow.hh
frontend/gtkmm/src/RestBreakWindow.cc
frontend/gtkmm/src/win32/W32Compat.cc
frontend/gtkmm/src/win32/W32Compat.hh
frontend/gtkmm/src/win32/W32ForceFocus.cc
frontend/gtkmm/src/win32/W32ForceFocus.hh

- Abolish existing win32 force focus code in W32Compat

- New class W32ForceFocus

The new class contains several different hacks to force win32 window
focus. Each hack is contained in its own function. 3 are implemented:

AltKeypress(): Simulate an ALT keypress to force focus
AttachInput(): Attach to the foreground thread to force focus
MinimizeRestore(): Minimize and restore a dummy window to force focus

AttachInput() is a rewrite of the force focus method that was in
W32Compat, and the other two are new. Each of the functions can spin
their trick in an attempt to make the passed in hwnd (eg a Workrave
break window) the foreground window.

Although the focus functions are public it is not always safe to call
them directly, as at least one of them -- AttachInput() -- could
deadlock our GUI main thread. Instead call ForceWindowFocus(), which
creates a sacrificial worker thread to call the focus functions.


- New preference: advanced/force_focus_functions

As described above we have several functions that can be used to force
the focus. This preference determines which of those functions will be
called by the thread started by ForceWindowFocus(). If the preference
does not exist then all functions are tried. The preference consists of
one or more names separated by a comma with no spaces. The order is not
important (subject to change). The names match to the focus functions'
enumerated names:

all_functions,
no_functions,
alt_keypress,
attach_input,
minimize_restore

When all_functions is encountered then all functions will always be
tried. When no_functions is encountered then no functions will be tried
aside from a vanilla SetForegroundWindow().

The REG_SZ preference is evaluated internally as a string. Example:
[HKEY_CURRENT_USER\Software\Workrave\advanced]
"force_focus_functions"="minimize_restore,attach_input"


- New preference: advanced/force_focus_on_break_start

This is a lighter alternative to advanced/force_focus that shouldn't
cause any disruption. On BreakWindow::BreakWindow() this preference is
read and cached locally as bool force_focus_on_break_start, and on
BreakWindow::start() we call W32ForceFocus::ForceWindowFocus() if
we're forcing focus on start.

Background:

We have to make sure our break windows are set on top with every call
to BreakWindow::refresh(), however if advanced/force_focus is enabled
then each call to set our window on top results in focus being forced
to that window. Depending on the method that could cause flickering,
simulated input, or any number of other undesirables. While I've made
changes to mitigate this in the codebase we can also now virtually
eliminate it by only attempting to force the focus once, on break start.

The REG_SZ preference is evaluated internally as boolean. Example:
[HKEY_CURRENT_USER\Software\Workrave\advanced]
"force_focus_on_break_start"="1"
New W32CriticalSection class for RAII sections

build/cmake/common/CMakeLists.txt
common/include/win32/W32CriticalSection.hh
common/src/win32/W32CriticalSection.cc

- New class W32CriticalSection

An RAII wrapper for Microsoft's CRITICAL_SECTION thread synchronization
object that handles the initialization, locking/unlocking and deletion.
The locking is thread re-entrant, unlike Microsoft's own
critical_section class which is not.

For more see comment block in common/src/win32/W32CriticalSection.cc
Add critical sections to W32ForceFocus functions

frontend/gtkmm/src/win32/W32ForceFocus.cc
frontend/gtkmm/src/win32/W32ForceFocus.hh

- (W32ForceFocus::GetFunctions)
Add a critical section to cache function retval.

- (W32ForceFocus::GetForceFocusValue)
Add a critical section to cache function retval.
Adjust BreakWindow::refresh() for W32ForceFocus

frontend/gtkmm/src/win32/W32ForceFocus.cc

- (BreakWindow::refresh)
Remove WindowHints::set_always_on_top() from the W32 section. That call
does not behave as desired if there are multiple break windows and
force_focus is enabled. Instead add a call to W32Compat::ResetWindow()
to ensure we hold topmost.

- (BreakWindow::refresh)
Remove the logic to call W32Compat::ResetWindow() for every mode except
GUIConfig::BLOCK_MODE_NONE. Instead call the function always. Even if
there's no block mode a topmost window may still need a reset.

- (BreakWindow::refresh)
Call W32ForceFocus::ForceWindowFocus() only if the advanced/force_focus
preference is enabled and the BreakWindow we're forcing focus to is the
main break window.

Prior to these changes if the user had advanced/force_focus enabled and
there were multiple break windows active then focus was forced to each
of them on each refresh(), resulting in a continuous round-robin change
of the foreground window and making it very difficult for the user to
interact with Workrave during a break.
Fix minor bug in W32CriticalSection::AdvancedGuard

common/include/win32/W32CriticalSection.hh
common/src/win32/W32CriticalSection.cc

- (W32CriticalSection::AdvancedGuard::TryLockFor)
Add acceptance of INFINITE as a remaining wait time: Update the
remaining wait time only if not INFINITE.

Prior to this change an infinite wait was not handled properly.
Add W32 functions to check winstation status

frontend/gtkmm/src/win32/W32Compat.cc
frontend/gtkmm/src/win32/W32Compat.hh
frontend/gtkmm/src/win32/W32ForceFocus.cc

- (W32Compat::_init)
Refactor W32Compat initialization.

- (W32Compat::WinStationQueryInformationW)
New function to query winstation information.

- (W32Compat::IsOurWinStationConnected)
New function to check if our process' window station is connected.

- (W32Compat::IsOurWinStationLocked)
New function to check if our process' window station is locked.

- (W32Compat::IsOurDesktopVisible)
New function to check if our thread's desktop is viewable by the user.
If the desktop is viewable then the window station associated with our
process is connected, unlocked and our desktop receives the input.

- (W32ForceFocus::thread_Worker)
Do not try to force the window focus if our desktop is not visible.
Add W32 function GetForegroundWindowTryHarder()

frontend/gtkmm/src/win32/W32ForceFocus.cc
frontend/gtkmm/src/win32/W32ForceFocus.hh

- (W32ForceFocus::GetForegroundWindowTryHarder)
New function to retry GetForegroundWindow() a number of times.

- (W32ForceFocus::AltKeypress)
- (W32ForceFocus::AttachInput)
- (W32ForceFocus::MinimizeRestore)
Use GetForegroundWindowTryHarder() instead of GetForegroundWindow() for
more accurate results.

Prior to this change the three force focus functions above would test
for the current foreground window by calling GetForegroundWindow().
Occasionally that call would return NULL because the window manager was
in the middle of a transition from one foreground window to another. To
remedy that I've implemented GetForegroundWindowTryHarder().
Fix minor bug in W32Compat::IsOurDesktopVisible()

frontend/gtkmm/src/win32/W32Compat.cc

- (W32Compat::IsOurDesktopVisible)
Fix incorrect buffer size comparisons of bytes needed to max characters.

Prior to this change the incorrect comparisons would cause the function
to fail if the bytes needed for a buffer was more than half its size.
Change W32ForceFocus::MinimizeRestore() method

frontend/gtkmm/src/win32/W32ForceFocus.cc

- (W32ForceFocus::MinimizeRestore)
Change dummy window coordinates to off screen.
Change ShowWindow() calls to SetWindowPlacement() calls.

Prior to these changes the dummy window could be visible to the user
during the brief moment when it was minimized and restored. It was very
apparent on XP if using its default window theme.
Add w32 topmost call in BreakWindow::refresh()

frontend/gtkmm/src/BreakWindow.cc

- (BreakWindow::refresh)
Add a call to SetWindowPos() with HWND_TOPMOST to ensure that our break
window stays topmost even over other topmost windows.

Prior to this change the call to W32Compat::SetWindowOnTop() --which
is similar to what is described above-- in BreakWindow::refresh() was
eliminated for compatibility with W32 force focus behavior.
Ref: e5df39fb31b10745697406ebe2dc7c4283a75d05

All of the behavior of W32Compat::SetWindowOnTop() is now in
BreakWindow::refresh() and is modified to be force focus compatible.
Move w32 refresh from BreakWindow to W32Compat

frontend/gtkmm/src/BreakWindow.cc
frontend/gtkmm/src/BreakWindow.hh
frontend/gtkmm/src/win32/W32Compat.cc
frontend/gtkmm/src/win32/W32Compat.hh

- (BreakWindow)
Add W32Compat class as a friend of BreakWindow.

- (BreakWindow::refresh)
Move the w32 specific code to W32Compat::RefreshBreakWindow().

- (W32Compat::RefreshBreakWindow)
New function for our w32 code from BreakWindow::refresh().
Check for visible tooltip during w32 break refresh

frontend/gtkmm/src/GtkUtil.cc
frontend/gtkmm/src/GtkUtil.hh
frontend/gtkmm/src/win32/W32Compat.cc

- (GtkUtil::get_visible_tooltip_window)
New function to get the application's visible tooltip window.

- (W32Compat::RefreshBreakWindow)
Don't enforce topmost while a tooltip is visible.

Prior to this change any break window tooltip was visible only very
briefly. Any tooltip would be quickly covered by the break window
because we were forcing our break window to become topmost over any
other window, including our topmost tooltip window.
Merge pull request #29 from jay/w32focus

Redo w32 force focus