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(); });


Reply via email to