The problem is described in the subject. I've got class to draw border around application's window. The border is implemented like shaped-wxFrame with "wxFRAME_NO_TASKBAR" style. According to the documentation, it
And when the initial border is created it's indeed absent on taskbar. However I noticed when I maximize/minimize application's window few times (for about 15-20, don't ask why - it's just a test case) then the border separates as a different applications and appears on taskbar (see attachment).Creates an otherwise normal frame but it does not appear in the taskbar under Windows or GTK+ (note that it will minimize to the desktop window under Windows which may seem strange to the users and thus it might be better to use this style only without wxMINIMIZE_BOX style). In wxGTK, the flag is respected only if the window manager supports _NET_WM_STATE_SKIP_TASKBAR hint.
Once in a period special helper class checks if application's size and position was changed:
Code: Select all
if (!m_displayMode.IsEqualGeometry(mode))
{
DUMPER_WARN("Screen sizes have been changed");
ResetBorder(rc.x, rc.y, rc.x + rc.width, rc.y + rc.height);
return DS_ERROR_MODE_CHANGED;
}
if(m_displayMode.position != mode.position)
{
m_displayMode.position = mode.position;
MoveBorder(rc.x, rc.y);
return DS_ERROR_MODE_CHANGED;
}
Code: Select all
void LinuxDisplayHelperMaster::ResetBorder(int x1, int y1, int x2, int y2)
{
m_borderWindow->Stop();
m_borderWindow->SetPosition(x1, y1, x2, y2);
m_borderWindow->Start();
}
Code: Select all
#pragma once
#include "ILinuxBorder.h"
#include <wx/frame.h>
#include <wx/timer.h>
class wxTimerEvent;
class LinuxBorderWindowApp: public wxFrame, public ILinuxBorder
{
public:
LinuxBorderWindowApp();
virtual ~LinuxBorderWindowApp();
void Start() override;
void Stop() override;
void ShowBorder(bool show) override;
void MoveBorder(int x, int y) override;
void SetPosition(int x1, int y1, int x2, int y2) override;
void UpdateRegionSizeAndPos();
protected:
void OnTimer(wxTimerEvent&);
private:
bool m_highlightFrame = false;
wxRect m_windowRect;
wxTimer m_appRefreshTimer;
int m_borderThickness;
};
Code: Select all
#include "stdafx.h"
#include "LinuxBorderWindowApp.h"
#include "Dumper.h"
#include "WxWidgetsControls/FromDIP.h"
namespace
{
constexpr int frameThickness = 2;
const wxColour bckgBrushDark(255, 128, 0);
const wxColour bckgBrushLight(255, 201, 14);
}
LinuxBorderWindowApp::LinuxBorderWindowApp():
wxFrame(nullptr, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize,
0
| wxFRAME_SHAPED
| wxSIMPLE_BORDER
| wxFRAME_NO_TASKBAR
| wxSTAY_ON_TOP
)
{
m_appRefreshTimer.SetOwner(this);
m_borderThickness = FromDIP(::frameThickness);
}
LinuxBorderWindowApp::~LinuxBorderWindowApp()
{
Stop();
}
void LinuxBorderWindowApp::Start()
{
SetShape(wxRegion());
if(!m_appRefreshTimer.IsRunning())
{
UpdateRegionSizeAndPos();
SetBackgroundColour(bckgBrushDark);
Bind(wxEVT_TIMER, &LinuxBorderWindowApp::OnTimer, this);
m_appRefreshTimer.Start(500);
Show(true);
}
}
void LinuxBorderWindowApp::Stop()
{
if(m_appRefreshTimer.IsRunning())
{
m_appRefreshTimer.Stop();
Unbind(wxEVT_TIMER, &LinuxBorderWindowApp::OnTimer, this);
}
Show(false);
}
void LinuxBorderWindowApp::SetPosition(int x1, int y1, int x2, int y2)
{
m_windowRect.x = x1;
m_windowRect.y = y1;
m_windowRect.width = x2 - x1;
m_windowRect.height = y2 - y1;
}
void LinuxBorderWindowApp::OnTimer(wxTimerEvent&)
{
SetBackgroundColour(m_highlightFrame ? bckgBrushLight : bckgBrushDark);
m_highlightFrame = !m_highlightFrame;
UpdateRegionSizeAndPos();
}
void LinuxBorderWindowApp::UpdateRegionSizeAndPos()
{
wxRegion shapeRegion;
shapeRegion.Union(wxRect(0, 0, m_windowRect.width, m_borderThickness)); // upper border
shapeRegion.Union(wxRect(0, 0, m_borderThickness, m_windowRect.height)); // left border
shapeRegion.Union(wxRect(0, 0 + m_windowRect.height - m_borderThickness, m_windowRect.width, m_borderThickness)); // bot border
shapeRegion.Union(wxRect(0 + m_windowRect.width - m_borderThickness, 0, m_borderThickness, m_windowRect.height)); // right border
SetSize(m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
SetShape(shapeRegion);
this->Update();
}
void LinuxBorderWindowApp::ShowBorder(bool show)
{
wxFrame::Show(show);
}
void LinuxBorderWindowApp::MoveBorder(int x, int y)
{
wxFrame::Move(x, y);
}
Code: Select all
int wxStart(int argc, char** argv)
{
return wxEntry(argc, argv);
}
bool LinuxSessionHelperModule::BeforeMainProc(int argc, char* argv[])
{
atexit(ExitHandler);
XInitThreads();
CXErrorHandlerUtils::InstallErrorHandler();
// here some unrelated code
if (id != invalidDisplayId.nix.displayId)
{
// here some unrelated code
std::thread(wxStart, argc, argv).detach();
}
}
return true;
}
So my questions are why border sometimes appears on taskbar even if wxFRAME_NO_TASKBAR is used and how to solve it?
P.S. actually, I don't expect successful solution, bit hope that we'll find it.
Thanks.