gtkD window centering message up and no app on taskbar

Johnson Jones via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Aug 8 16:00:25 PDT 2017


On Tuesday, 8 August 2017 at 21:37:40 UTC, Mike Wey wrote:
> On 07-08-17 23:52, Johnson Jones wrote:
>> On Monday, 7 August 2017 at 20:57:08 UTC, Mike Wey wrote:
>>> On 07-08-17 22:46, Johnson Jones wrote:
>>>> [...]
>>>
>>> This appears to be a GTK issue, a work around might be to get 
>>> the Window handle from gtk and use the Windows API to set the 
>>> taskbar visibility.
>>>
>> 
>> Yeah, I was thinking about that but haven't yet figured out 
>> how to find the window handle ;/
>
> To get the Window handle you could use this for 32bit Windows:
>
> ```
> import gtk.c.functions;
>
> // Danger, Will Robinson!
>
> HANDLE handle = 
> *(cast(HANDLE*)((cast(void*)gtk_widget_get_window(w.getWidgetStruct()))+4));
>
> 		
> ```
> Where w is your application window, i used this in the map 
> event signal so the handle is actually set. To complicate 
> things there is a race condition in gdk some ware so at random 
> the handle isn't valid.
>
>
> I haven't been able to set the taskbar icon with is tough.
>
> The two attempts:
>
> -Setting the parent window to null as windows with no parent 
> should have an taskbar icon:
>
> ```
> ShowWindow(handle, SW_HIDE);
> SetParent(handle, null);
> ShowWindow(handle, SW_SHOW);
> ```
>
> Or set the extended window style to WS_EX_APPWINDOW as that 
> should fore an taskbar icon according to msdn.
>
> ```
> ShowWindow(handle, SW_HIDE);
> SetWindowLong(handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
> ShowWindow(handle, SW_SHOW);
> ```


Yeah, they keep returning null or some integer < 100(probably 
junk values).

There surely has to be a way to get the windows handle? We could 
use Win32 api and "search" for the window and get the handle but 
that isn't that safe unless we can specify the windows classname 
or title uniquely.

Things like ispy can find windows by coordinates but I think they 
essentially use the above methods and region compares. e.g., 
there is no FindWindowByCoordinates... which still wouldn't be 
very accurate.



// Fixup missing taskbar icon
void SetTaskBarIcon(gtk.ApplicationWindow window)
{
	
	version(Windows)
		version(X86)
		{
			import core.sys.windows.winuser, gdk.Window;
			auto x = window.getWidgetStruct();
			auto y = 
((cast(void*)gtk.gtk_widget_get_window(window.getWidgetStruct()))+4);
			auto handle = 
*(cast(core.sys.windows.winuser.HANDLE*)((cast(void*)gtk.gtk_widget_get_window(window.getWidgetStruct()))+4));
			ShowWindow(handle, SW_HIDE);
			SetParent(handle, null);			
			SetWindowLong(handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
			ShowWindow(handle, SW_SHOW);
		}
	return;
}

Sometimes I get y = 4, which I think is what you were saying 
before. Sometimes I get handle = < 100.

I've tried in a few places but not after Main.run(), which maybe 
is needed for gtk to register the window and all that? I guess I 
can run that function in a callback and see if it is valid... 
Didn't work.

I can't really find anything on line about getting a windows 
handle from gtk ;/


There is this: 
https://stackoverflow.com/questions/23021327/how-i-can-get-drawingarea-window-handle-in-gtk3

         Gdk.threads_enter()
         #get the gdk window and the corresponding c gpointer
         drawingareawnd = drawingarea.get_property("window")
         #make sure to call ensure_native before e.g. on realize
         if not drawingareawnd.has_native():
             print("Your window is gonna freeze as soon as you 
move or resize it...")
         ctypes.pythonapi.PyCapsule_GetPointer.restype = 
ctypes.c_void_p
         ctypes.pythonapi.PyCapsule_GetPointer.argtypes = 
[ctypes.py_object]
         drawingarea_gpointer = 
ctypes.pythonapi.PyCapsule_GetPointer(drawingareawnd.__gpointer__, None)
         #get the win32 handle
         gdkdll = ctypes.CDLL ("libgdk-3-0.dll")
         hnd = 
gdkdll.gdk_win32_window_get_handle(drawingarea_gpointer)
         #do what you want with it ... I pass it to a gstreamer 
videosink
         Gdk.threads_leave()

which suggests that maybe gdk_win32_window_get_handle can be used


Ok, I was able to get it to work using that code. I had to do 
some wonky dll imports and stuff but that function seems to be 
the correct one. I could not use it until after the window was 
created(I used it in a button handler), else it crashed the app 
for some reason.



			import core.sys.windows.winuser, gdk.Window;
			auto handle = 
cast(core.sys.windows.winuser.HANDLE)gdk_win32_window_get_handle(gtk.gtk_widget_get_window(window.getWidgetStruct()));
			ShowWindow(handle, SW_HIDE);
			SetParent(handle, null);			
			SetWindowLong(handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
			ShowWindow(handle, SW_SHOW);

Seems to work.

So you might want to add gdk_win32_window_get_handle as an export 
in gtkD so it can be used easier.


The full code is:

void SetTaskBarIcon(gtk.ApplicationWindow window)
{
	
	version(Windows)
		version(X86)
		{
			import core.sys.windows.winuser, gdk.Window;
			auto handle = 
cast(core.sys.windows.winuser.HANDLE)gdk_win32_window_get_handle(gtk.gtk_widget_get_window(window.getWidgetStruct()));
			ShowWindow(handle, SW_HIDE);
			SetParent(handle, null);			
			SetWindowLong(handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
			ShowWindow(handle, SW_SHOW);
		}
	return;
}



Probably could be designed better. If I use it like

MainWindow.addOnShow((Widget widget) { 
MainWindow.SetTaskBarIcon(); });

the window never shows and a lot of gtk errors are given about 
updating the window.


(test.exe:4440): Gdk-WARNING **: gdkwindow-win32.c:439: 
UpdateLayeredWindow failed with code 87: The parameter is 
incorrect.


which comes from this line:

SetWindowLong(handle, GWL_EXSTYLE, WS_EX_APPWINDOW);

So maybe we have to GetWindowLong and modify it slightly

SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, 
GWL_EXSTYLE) | WS_EX_APPWINDOW);

which doesn't work. The error is no longer their but the icon 
doesn't show up.

But, finally, this does seem to work:


// Fixup missing taskbar icon
void SetTaskBarIcon(gtk.ApplicationWindow window)
{
	
	version(Windows)
		version(X86)
		{
			import core.sys.windows.winuser, gdk.Window;
			auto handle = 
cast(core.sys.windows.winuser.HANDLE)gdk_win32_window_get_handle(gtk.gtk_widget_get_window(window.getWidgetStruct()));
			ShowWindow(handle, SW_HIDE);
//			SetParent(handle, null);			
			SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, 
GWL_EXSTYLE) | WS_EX_APPWINDOW);
			ShowWindow(handle, SW_SHOW);
		}
	return;
}

Of course, along with this:


MainWindow.addOnShow((Widget widget) { 
MainWindow.SetTaskBarIcon(); });




More information about the Digitalmars-d-learn mailing list