Linux. Draw border around specific window Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 12:34 pm

also don't create wxTimer by new. to avoid new/delete.
just declare timer as field in your frame class.
wxTimer _m_appRefreshTimer;
and stop it in destructor.
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Wed Jun 12, 2019 12:43 pm

xdpyinfo | grep dimensions returns 1024 x 768.
I tried to call GetPosition() after SetShape() and it returned 262, 28. The same position for border I see in paint (I made screenshot of the desktop and inserted it in the paint application).
Thanks for timer advise.

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 12:54 pm

what i do not know - in which coordinates all this regions for shape must be given... it could be parent coordinates(screen in your case), but also could be relative to frame coordinates. if i remember there is no mentioning in documentaion.
may be try to change origin from windowRect.x, windowRect.y, to 0,0?

Code: Select all

shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, m_windowRect.width, thickness)); // upper border
shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, thickness, m_windowRect.height)); // left border
 shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y + m_windowRect.height - thickness, m_windowRect.width, thickness)); // bot border
 shapeRegion.Union(wxRect(m_windowRect.x + m_windowRect.width - thickness, m_windowRect.y, thickness, m_windowRect.height)); // right border
comment this code and write this block with zeroes instead of x,y
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Wed Jun 12, 2019 1:23 pm

Tried it. It didn't help.
I tried to SetSize with 0, 0 offset, however it didn't help too.

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 3:25 pm

put here your final code
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Wed Jun 12, 2019 3:35 pm

Code: Select all

#pragma once

#include <wx/frame.h>

class wxTimer;
class wxTimerEvent;

class LinuxBorderWindow: public wxFrame
{
public:
    LinuxBorderWindow(int borderThickness = -1);
    ~LinuxBorderWindow();

    void Start();
    void Stop();

    void SetPosition(int x, int y, int w, int h);
    void UpdateRegionSizeAndPos();
    void MoveBorder(int x, int y);
protected:
    void OnTimer(wxTimerEvent&);
private:
    bool m_highlightFrame = false;
    int m_borderThickness;
    wxRect m_windowRect;
    wxTimer* m_appRefreshTimer = nullptr;
};

Code: Select all

#include "stdafx.h"
#include "LinuxBorderWindow.h"
#include "Dumper.h"
#include "WxWidgetsControls/FromDIP.h"
#include <wx/timer.h>

namespace
{
    constexpr int frameThickness = 5;
    const wxColour bckgBrushDark(255, 128, 0);
    const wxColour bckgBrushLight(255, 201, 14);
}

LinuxBorderWindow::LinuxBorderWindow(int borderThickness):
    wxFrame(nullptr, wxID_ANY, wxEmptyString,
                      wxDefaultPosition, wxDefaultSize,
                      0
                      | wxFRAME_SHAPED
                      | wxSIMPLE_BORDER
                      | wxFRAME_NO_TASKBAR
                      | wxSTAY_ON_TOP
                ),
    m_borderThickness(borderThickness)
{
    if(m_borderThickness == -1)
    {
        m_borderThickness = ::frameThickness;
    }
}

LinuxBorderWindow::~LinuxBorderWindow()
{
    Stop();
}

void LinuxBorderWindow::Start()
{
    UpdateRegionSizeAndPos();
    SetBackgroundColour(bckgBrushDark);
    m_appRefreshTimer = new wxTimer(this);
    Bind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
    m_appRefreshTimer->Start(500);
}

void LinuxBorderWindow::Stop()
{
    if(m_appRefreshTimer != nullptr)
    {
        m_appRefreshTimer->Stop();
        Unbind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
        delete m_appRefreshTimer;
        m_appRefreshTimer = nullptr;
    }
}

void LinuxBorderWindow::SetPosition(int x, int y, int w, int h)
{
    DUMPER_INFO("New pos (%d, %d) - %dx%d", x, y, w, h);
    wxPoint leftTop = ScreenToClient(wxPoint(x, y));
    DUMPER_INFO("Coords after transform (%d, %d)", leftTop.x, leftTop.y);
    m_windowRect.x = x;//leftTop.x;
    m_windowRect.y = y;//leftTop.y;
    m_windowRect.width = w;
    m_windowRect.height = h;
}

void LinuxBorderWindow::OnTimer(wxTimerEvent&)
{
    SetBackgroundColour(m_highlightFrame ? bckgBrushLight : bckgBrushDark);
    m_highlightFrame = !m_highlightFrame;
}

void LinuxBorderWindow::UpdateRegionSizeAndPos()
{
    DUMPER_INFO("New rect (%d, %d) - %dx%d", m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
    SetShape(wxRegion());
    SetSize(m_windowRect.x + m_windowRect.width, m_windowRect.y + m_windowRect.height);
    //SetSize(m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
    wxRegion shapeRegion;
    int thickness = FromDIP(m_borderThickness);
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, m_windowRect.width, thickness)); // upper border
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, thickness, m_windowRect.height)); // left border
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y + m_windowRect.height - thickness, m_windowRect.width, thickness)); // bot border
    shapeRegion.Union(wxRect(m_windowRect.x + m_windowRect.width - thickness, m_windowRect.y, thickness, m_windowRect.height)); // right border
    SetShape(shapeRegion);
    wxRect rc = shapeRegion.GetBox();
    DUMPER_INFO("box params: (%d, %d) %dx%d", rc.GetLeftTop().x, rc.GetLeftTop().y, rc.width, rc.height);
    wxPoint pos = GetPosition();
    DUMPER_INFO("Pos: %d, %d", pos.x, pos.y);
}

void LinuxBorderWindow::MoveBorder(int x, int y)
{
    wxPoint pos = ClientToScreen(wxPoint(x, y));
    Move(x, y);
}

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 4:03 pm

this your old code, i briefly corrected, works
look at added this->Update() at timer and UpdateSize.. functions
regions also are relative to window coordinates - origin is 0,0
also i declared timer as field of frame.

Code: Select all

namespace
{
    constexpr int frameThickness = 5;
    const wxColour bckgBrushDark(255, 128, 0);
    const wxColour bckgBrushLight(255, 201, 14);
}

LinuxBorderWindow::LinuxBorderWindow(int borderThickness):
    wxFrame(nullptr, wxID_ANY, wxEmptyString,
                      wxDefaultPosition, wxDefaultSize,
                      0
                      | wxFRAME_SHAPED
                      | wxSIMPLE_BORDER
                      | wxFRAME_NO_TASKBAR
                      | wxSTAY_ON_TOP
                ),
    m_borderThickness(borderThickness)
{
    if(m_borderThickness == -1)
    {
        m_borderThickness = ::frameThickness;
    }
}

LinuxBorderWindow::~LinuxBorderWindow()
{
    Stop();
}

void LinuxBorderWindow::Start()
{
    //UpdateRegionSizeAndPos();
    SetBackgroundColour(bckgBrushDark);
    Bind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
    _appRefreshTimer.Start(500);
}

void LinuxBorderWindow::Stop()
{
	_appRefreshTimer.Stop();
	 Unbind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
}

void LinuxBorderWindow::SetPosition(int x, int y, int w, int h)
{
    //wxPoint leftTop = ScreenToClient(wxPoint(x, y));
    wxPoint leftTop(x,y);
	
	m_windowRect.x = leftTop.x;
	m_windowRect.y = leftTop.y;
	m_windowRect.width = w;
	m_windowRect.height = h;
}

void LinuxBorderWindow::OnTimer(wxTimerEvent&)
{
	SetBackgroundColour(m_highlightFrame ? bckgBrushLight : bckgBrushDark);
	m_highlightFrame = !m_highlightFrame;
	this->Update();
}

void LinuxBorderWindow::UpdateRegionSizeAndPos()
{
    //SetShape(wxRegion());

#if 0
    SetSize(m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
    wxRegion shapeRegion;
    int thickness = 4;//FromDIP(m_borderThickness);
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, m_windowRect.width, thickness)); // upper border
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y, thickness, m_windowRect.height)); // left border
    shapeRegion.Union(wxRect(m_windowRect.x, m_windowRect.y + m_windowRect.height - thickness, m_windowRect.width, thickness)); // bot border
    shapeRegion.Union(wxRect(m_windowRect.x + m_windowRect.width - thickness, m_windowRect.y, thickness, m_windowRect.height)); // right border
    SetShape(shapeRegion);
#endif

	SetSize(m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
	wxRegion shapeRegion;
	int thickness = 4;//FromDIP(m_borderThickness);
	shapeRegion.Union(wxRect(0, 0, m_windowRect.width, thickness)); // upper border
	shapeRegion.Union(wxRect(0, 0, thickness, m_windowRect.height)); // left border
	shapeRegion.Union(wxRect(0, 0+ m_windowRect.height - thickness, m_windowRect.width, thickness)); // bot border
	shapeRegion.Union(wxRect(0 + m_windowRect.width - thickness, 0, thickness, m_windowRect.height)); // right border
	SetShape(shapeRegion);
	this->Update();
}

void LinuxBorderWindow::Move(int x, int y)
{
    //wxPoint pos = ScreenToClient(wxPoint(x, y));
    //wxFrame::Move(pos.x, pos.y);
	wxFrame::Move(x,y);
}
ubuntu 16.04, wxWidgets 3.0.4

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 4:27 pm

also you forgot to call this function for timer
https://docs.wxwidgets.org/3.0/classwx_ ... 4733eab27e
in current code timer events do not reach your handler.
do it before binding onTimer method to event->
_timer.SetOwner(this);
Bind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Wed Jun 12, 2019 6:01 pm

It works almost fine for full desktop, but not for region (for example, if I want to draw border around rect with x = 198, y = 243, w = 500, h = 300), it draws border in incorrect offset.
Here is my code:

Code: Select all

#include "stdafx.h"
#include "LinuxBorderWindow.h"
#include "Dumper.h"
#include "WxWidgetsControls/FromDIP.h"

namespace
{
    constexpr int frameThickness = 5;
    const wxColour bckgBrushDark(255, 128, 0);
    const wxColour bckgBrushLight(255, 201, 14);
}

LinuxBorderWindow::LinuxBorderWindow(int borderThickness):
    wxFrame(nullptr, wxID_ANY, wxEmptyString,
                      wxDefaultPosition, wxDefaultSize,
                      0
                      | wxFRAME_SHAPED
                      | wxSIMPLE_BORDER
                      | wxFRAME_NO_TASKBAR
                      | wxSTAY_ON_TOP
                ),
    m_borderThickness(borderThickness)
{
    if(m_borderThickness == -1)
    {
        m_borderThickness = ::frameThickness;
    }
}

LinuxBorderWindow::~LinuxBorderWindow()
{
    Stop();
}

void LinuxBorderWindow::Start()
{
    UpdateRegionSizeAndPos();
    SetBackgroundColour(bckgBrushDark);
    m_appRefreshTimer.SetOwner(this);
    Bind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
    m_appRefreshTimer.Start(500);
}

void LinuxBorderWindow::Stop()
{
    if(m_appRefreshTimer.IsRunning())
    {
        m_appRefreshTimer.Stop();
        Unbind(wxEVT_TIMER, &LinuxBorderWindow::OnTimer, this);
    }
}

void LinuxBorderWindow::SetPosition(int x, int y, int w, int h)
{
    wxPoint leftTop = ScreenToClient(wxPoint(x, y));
    m_windowRect.x = x;//leftTop.x;
    m_windowRect.y = y;//leftTop.y;
    m_windowRect.width = w;
    m_windowRect.height = h;
}

void LinuxBorderWindow::OnTimer(wxTimerEvent&)
{
    SetBackgroundColour(m_highlightFrame ? bckgBrushLight : bckgBrushDark);
    m_highlightFrame = !m_highlightFrame;
    this->Update();
}

void LinuxBorderWindow::UpdateRegionSizeAndPos()
{
    SetShape(wxRegion());;
    SetSize(m_windowRect.x, m_windowRect.y, m_windowRect.width, m_windowRect.height);
    wxRegion shapeRegion;
    int thickness = FromDIP(m_borderThickness);
    shapeRegion.Union(wxRect(0, 0, m_windowRect.width, thickness)); // upper border
    shapeRegion.Union(wxRect(0, 0, thickness, m_windowRect.height)); // left border
    shapeRegion.Union(wxRect(0, 0+ m_windowRect.height - thickness, m_windowRect.width, thickness)); // bot border
    shapeRegion.Union(wxRect(0 + m_windowRect.width - thickness, 0, thickness, m_windowRect.height)); // right border
    SetShape(shapeRegion);
    this->Update();
}

void LinuxBorderWindow::MoveBorder(int x, int y)
{
    wxFrame::Move(x, y);
}
I uncommented UpdateRegionSizeAndPos(); in Start method
UPD something wrong in my init code. With hardcoded values everything is OK. I'll check it tomorrow and update you with results.
Thanks for help

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Wed Jun 12, 2019 6:28 pm

i tested my code giving rect - 100,100,100,100 and then 100,200,100,200.
everything fit well. second region was below first, and touched his bottom with upper border...
i'm sure you are giving wrong coordinates to your SetPosition.
it must be absolute coordinates of your targeted frame, not any client area or something.
added:
you must use wxRect GetRect() of target window(if it has not parents!!!) and give this rect to your blinking border frame.
it must work
https://docs.wxwidgets.org/3.0/classwx_ ... fbe38745eb
or get screen position - next function in help. to take screen coordinates, and take size and then give it to blinking frame
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Thu Jun 13, 2019 6:19 am

Indeed, there was an error in code that calculates border area.
Now everything looks fine.
Here is one more problem left. When I draw border for whole desktop, then bottom and top panes of desktop are painted with something unclear:
withborder.png
desktop.png
As you can see when I draw border there is no bottom pane with running apps and top pane with date and shutdown button

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Thu Jun 13, 2019 7:05 am

it's some interference with your OS windowing system. this areas are used by system to draw taskbar, etc... and they are not given to application windows. I do not know how to solve it, because here interests of OS native interface and your wxWIdgets app are opposed.
any way application cannot draw something there, if it is not in full screen mode. It could not be bad for you, if you are drawing border for app window, not the screen entirely?
imho, the native windowing system understands, that something is drawn above its top and bottom bars, so hides them, and is not painting them. make the frame slightly smaller and you would see visible parts of this bars.
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Thu Jun 13, 2019 7:24 am

When I drew border using gtk it wasn't possible to draw border on these panes until I changed border type to GTK_WINDOW_POPUP. As it said in description:

Code: Select all

If you're implementing something like a popup menu from scratch (which is a bad idea, just use GtkMenu), you might use GTK_WINDOW_POPUP. GTK_WINDOW_POPUP is not for dialogs, though in some other toolkits dialogs are called "popups". In GTK+, GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
I tried to remove wxSTAY_ON_TOP style, but it didn't help?
Do you know if there something like GTK_WINDOW_POPUP in wxWidgets?

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 153
Joined: Tue Oct 18, 2016 2:31 pm

Re: Linux. Draw border around specific window

Post by alys666 » Thu Jun 13, 2019 7:43 am

this?
https://docs.wxwidgets.org/trunk/classw ... indow.html
but why you need to draw something there, if you want to draw border of regular application window?
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 83
Joined: Tue Aug 28, 2018 1:02 pm

Re: Linux. Draw border around specific window

Post by rudolfninja » Thu Jun 13, 2019 7:53 am

alys666 wrote:
Thu Jun 13, 2019 7:43 am
this?
https://docs.wxwidgets.org/trunk/classw ... indow.html
but why you need to draw something there, if you want to draw border of regular application window?
I meant style I can use in wxFrame constructor to make it popup-like.
I need to draw border there because my app can handle three types of screen sharing: application, custom region and whole desktop. This border works fine with first two types, but not with entire desktop.

Post Reply