Win32 ToolTip disappears never to re-appear with Commctl 6 - windows

I'm creating a ToolTip window and adding tools to it using the flags
TTF_IDISHWND | TTF_SUBCLASS. (c++, win32)
I have a manifest file such that my program uses the new WindowsXP themes
(comctrl32 version 6).
When I hover over a registered tool, the tip appears.
Good.
When I click the mouse, the tip disappears.
Ok.
However, moving away from the tool and back
again does not make the tip re-appear. I need to hover over a different tool
and then come back to my tool to get the tip to come back.
When I remove my manifest file (to use the older non-XP comctrl32), the
problem goes away.
After doing some experimentation, I discovered the following differences
between ToolTips in Comctl32 version 5 (old) and Comctl32 version 6 (new):
New TTF_TRANSPARENT ToolTips (when used In-Place) actually return
HTCLIENT from WM_NCITTEST if a mouse button is down, thus getting
WM_LBUTTONDOWN and stealing focus for a moment before vanishing. This causes
the application's border to flash.
Old TTF_TRANSPARENT ToolTips always return HTTRANSPARENT from WM_NCHITTEST,
and thus never get WM_LBUTTONDOWN themselves and never steal focus. (This seems to be just aesthetic, but may impact the next point...)
New ToolTips seem not to get WM_TIMER events after a mouse-click, and
only resume getting (a bunch of) timer events after being de-activated and
re-activated. Thus, they do not re-display their tip window after a mouse
click and release.
Old ToolTips get a WM_TIMER message as soon as the mouse is moved again
after click/release, so they are ready to re-display their tip.
Thus, as a comctl32 workaround, I had to:
subclass the TOOLTIPS_CLASS window and always return HTTRANSPARENT from
WM_NCHITTEST if the tool asked for transparency.
avoid using TTF_SUBCLASS and rather process the mouse messages myself so
I could de-activate/re-activate upon receiving WM_xBUTTONUP.
I assume that the change in internal behavior was to accommodate the new "clickable" features in ToolTips like hyperlinks, but the hover behavior appears to be thus broken.
Does anyone know of a better solution than my subclass workaround? Am I missing some other point?

You're not the only one who has hit compatablity issues with tooltips between these DLLS.
I too have had nothing but trouble with the new tooltips in the themable common controls. We have already been monkeying with mouse messages and active/deactivating the tips before adding the manifest and theming our application - so it sounds like what your doing isn't too crazy.
We're still living with problems with TTN_NEEDTEXT messages being send constantly as the mouse moves (not just when hovering), positioning problems with large tips (maybe not something new), and odd unicode messages being sent instead of the ANSI versions (which I plan to post as a question at some point).

I don't know, but this sounds like a really "hard" problem (in the sense that all real-world) problems are really hard. I bet the underlying problem is something to do with the setting of the focus. Windows that manually do that are evil and generally suffer from all manner of bugs.

Related

SDL2 Raising a window without giving it focus

I need to display a tooltip over a window. I'm creating a second window with the tool tip and using SDL_RaiseWindow() to bring it to the top. However, doing that causes the tooltip to steal focus which is not what I want. Is there a way to bring a window to the top without changing focus?
Also, is there a way to set focus (mouse and/or keyboard) without changing the Z order of the windows?
The answer offered by Neil will only work under X11 as SDL_SetWindowInputFocus() is only implemented for that environment. In essence, the desired behaviour is otherwise not achievable. I have seen that there is a feature request in the SDL forums for an overload of the SDL_RaiseWindow() function to include an optional bool parameter to indicate if the raised window should also receive the input focus, or not. I hope they do implement that.
In any case, the support for multiple windows under SDL 2.x is a little weak. There is no built in support for the Z-order of different windows, and trying to build one based on the "painter's method" works, but leaves one no control over the input focus.
Old question, but this came up during my own search. You could try SDL_RaiseWindow() to bring your tooltip to the top, then use SDL_SetWindowInputFocus() on the main window to switch focus back to it.
I got this working sufficiently for my tooltips on mac by using SDL_WINDOW_ALWAYS_ON_TOP flag with SDL2:
SDL_CreateWindow(tooltip_window->name, x, y, w, h,
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS |
SDL_WINDOW_ALWAYS_ON_TOP);
SDL_RaiseWindow(windowThatShouldHaveFocus);
// ...render what you want on that tooltip (SDL_RenderClear, SDL_RenderCopy, SDL_RenderPresent) & hide it with SDL_HideWindow
And when showing the tooltip:
SDL_ShowWindow(tooltipWindow);
SDL_RaiseWindow(windowThatShouldHaveFocus);

Change Background of WP7 Application if Theme is altered

I need to change the Background Image of my Application if user changes theme from "Light" to "Dark" or vice-vesa in code behind. I hope these should be done in Page Loded event
#TimDams pointed you to one of the nice ways to detect what-theme-is-now-set, but I didn't notice there any information how to detect a change to the theme during the application runtime. The user could start your app, then bump forward to the menu, change the theme, and get back to your app. While you may think that your app will be tombstoned and then restarted and renavigated to your page with full cycle with all pageloads -- it is not 100% true.
Firstly, the PageLoaded is NOT a good place to do the initial check-and-set-styles, because, if you get that event called, then the page, probably, has already rendered once. If I remember well, the PageLoaded is invoked just after the first render. If this is true, then you will have to detect the colors earlier, for example in the LayoutUpdated (warning: this event is a great spammer. I mean, it gets called gazillions times. Attach a single-shot handler, you know, such that will instantly unattach-self on first invocation). Maybe you will be able to do it in the Page's .ctor, just after InitializeComponent. Or in the OnApplyTemplate or MeasureOverride, or at least ArrangeOverride -- the visuals should be mostly/fully available there.
Buuuut. I've intentionally 'bolded-out' the word "initial". With Mango, there's some multitasking getting more and more common, but even the pre-Mango 7.0 version does not guarantee that your app will be tombstoned. From my observations in early 7.0, for example, starting the MediaPlayer from WebBrowser component does not tombstone your app:) If you have some time to read, check WP7 recover from Tombstone and return to page for details on the "pause" vs "tombstone".
Anyways, if your app gets "paused" and the user switches themes in the meantime, I think (I've NOT checked) that your page will (in most of the cases) be just temporarily hidden and upon returning to the screen, it will probably not be re-created and will not be re-(Page)Loaded. If it is true, then you will have not so easy problem to solve, because your app may be paused, the OS rethemed, and your app unpased virtually in any moment of time and the only events you will get in the mean time are .... global events of App.Deactivated and App.Activated. It is possible that completely none of per-page events will fire [but I've not checked - before you do anything I suggest below, CHECK IT].
If this pessimistic view is really true, than in those events, you will have to detect the current theme (->Tim's post), then somehow inform your current Page that themes changed - or not. If you have your ViewModel at least a bit separated from the rest of the app (as it should be:) ) you have an easy option to do it: create in that ViewModel a set of properties (dp or inotif) like Brush Background, Brush Foreground, Brush Hightlight, and other that you need, and instead of harcoding colours in your XAML - bind to those properties. You may event want to create a separate class for all those many Brushes and other Styles, let's say "pub class MyCurrentAppTheme" and keep that props there, and expose such object from ViewModel - whatever. Just Bind your colors to whatever -- but whatever that will be "logically global" and that will be easily accessible from the App.Acticated event handler. Having that done, in the App.Activated, detect the current theme and if changed, so through all the colors kept in VM and set them appropriatelly. Voil'a, whole your App gets recoloured properly.
But mind that still - there might be some transient blinks and flashes between the rendering of cached old theme, refreshing databound objects, and redrawing fresh theme. I hope not, but I sense it may occur, especially when returning from fast-switch tool (long back press): I think that the device captures the 'last screenshot' of your app in the backbuffer and uses that throughout all the time the app is 'minimalized' to do transitions animations, to show the fast-app-switch overview and so on.. again, I've not checked, but I doubt that during such animations the pagecontents are 'live', it could be very demaning on CPU/GPU resources. Any one knows anything on that? It could be a nice test to have some looping animation on the page and then to switch out and check in the fast-switch overview, whether the animation moves or is halted!:)
If your application is tombstoned, all your controls will be recreated and the new theme will be applied. If you'd like to manage your light/dark specific styles in a similar vein to normal themes, you might want to take a look at a custom ResourceDictionary I blogged about a while back.
Unfortunately, as of Mango there, is a bug (?) related to fast application switching that causes the theme to remain unchanged in your application. The bug is outlined in this question and its linked posts:
Is there a bug when changing themes when app is deactivated and reactivated in Windows Phone Mango
My ResourceDictionary is still useful for the initial startup but it appears, unfortunately, that nothing can be done to workaround the Mango bug.
For this no event exists. You need to figure this out manually by comparing the PhoneBackgroundBrush color to see if the user has the dark or light theme and compare it with your last stored value.
Were you able to do some test on the App.Activate - Deactivate?
I decided to use a different path to solve the issue of dynamic theme change.
I've assigned to all text and buttons only system resource colors.
For the icons inside the buttons in the window instead of using PNG images-icons I used the in XAML and assing it a Foreground color from system resource.
For the buttons in the SystemMenuBar there is no issue as they are always on a dark gray background so the black PNG images work just fine.
Hoping this helps.
You can check if the dark theme is in use with this simple check:
public static bool CurrentThemeIsDark
{
get
{
return (Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible;
}
}

Changing UI in reaction to Storyboard.Completed event. Do we need BeginInvoke?

I have a ContentPresenter that switches between 2 states ("editor" and "viewer"). The states have different heights and different values of Content and ContentTemplate properties.
In one state change I resize the control by playing a Storyboard and in reaction to Storyboard.Completed event I change Content/Template properties.
It works basically ok, except I observed occasional flickering. When playing in debugger I observed that modifying above properties in Completed handler may cause strange screen effects (portions of the screen empty, extra shading, lines etc.) that the user observes as flickering.
However, whenever I postponed the ContentPresenter changes by using Dispatcher.BeginInvoke(), the problems seem to disappear. (More testing needed.)
Anyone has an explanation? On the web you'll find numerous code examples that perform UI changes in Storyboard.Completed handler, hence I find it a bit strange.
I suspect it may be more due to timing than needing to be on the UI thread. Try doing a Sleep for a second or so before changing the Content/Template properties instead of using Dispatcher.BeginInvoke(). If the flicker is gone then perhaps trying to change those properties while the Content was busy resizing itself during the storyboard was the culprit - perhaps assigning a fixed size or otherwise disabling the constant resizing during the storyboard would help. That's just a guess though, I'd have to see a sample to really figure it out. If you can make a small sample to reproduce it I'd gladly look at it.

Updating the region behind a resized window

We have a fairly complex GUI, so when certain windows are resized their Redraw() is set to false till the operation is completed. The problem with this is that if the OS "Show window content while dragging" setting is checked, when decreasing the window's size the windows behind it are not repainted. This means I have to force the repaint myself so the remains of the resized window are deleted. I have no problem getting the dimensions of the region that was uncovered. What I'm looking for is best way to cause all windows within that region to repaint their part.
Not being much of a GUI programmer, I can traverse the uncovered region and list the windows in it. Then, I can ask each one of them to repaint its part. But I'm quite certain there has to be a better way to do this...
It is worth mentioning the app is written in PowerBuilder. This means I can call whatever Win32 function I'd like, but have limited control over the GUI behavior and the message handling. If there's a better way to prevent the window's content resize from being visible, or there's a way to make a non-redrawn window clean after itself, I'd love to hear it (just have the limitations above in mind).
I'm curious what version of PowerBuilder you are working in? I do resizing all the time and never run into issues like you are describing.
Maybe you can lay out some more detail on why you need to set your redraws to false within the PowerBuilder environment.
Hope I can help.

How does one use onmousedown/onmouseup correctly?

Whenever I write mouse handling code, the onmousedown/onmouseup/onmousemove model always seemed to force me to produce unnecessarily complex code that would still end up causing all sorts of UI bugs.
The main problem which I see even in major pieces of software these days is the "ghost mouse" event where you drag to outside the window and then let go. Once you return back into the window, the application still thinks you have the mouse down even though the button is up. This is especially annoying when you're trying to highlight something that goes to the border of the screen.
Is there a RIGHT way to write mouse code or is the entire model just flawed?
Ordinarily one captures the mouse events on mouse down so the mouse move and mouse up go through your code regardless of the caret moving out of you application window.
More recently this is a problem when running a VM or remote session, its difficult for apps in these to track the mouse outside of the machine screen area represented by a window on a host.
I'm not sure what environment you're attempting to track mouse buttons in, but the best way to handle this is to have a mouse listener that tracks onmouseup 100% of the time after you've detected onmousedown.
That way, it doesn't matter what screen region the user releases the mouse button in. It will reset no matter where it happens.

Resources