In XLib based application, I need to make the child window to be resized after the parent window. (For example, in order to make the child window to take the whole client area of the parent window)
I am processing the ConfigureNotify event of the parent window and resizing the child window when needed.
In generally it works properly. But there is a delay between resizing the parent window (for example when the user resizes the window dragging the edge) and the event received by the application.
Because of this delay, the child window(s) takes its proper size only some time after the user stops to move the edges. This way, some bad flicker appears on the screen and the user interface looks really sluggish.
I can see the similar behavior in many Linux programs.
How this problem can be fixed? Or at least, how to make the delay significantly smaller?
I tried to ignore some of the ConfigureNotify events by processing only the last received event and it helps a little, but not enough.
Update:
After some research I found that the problem is due to the asynchronous nature of the WM-application interaction. While the application resizes and redraws the child window, the window manager continues to resize the parent window. So, when the process of the resize/realign/redraw finishes, the parent window has another size, another event is posted to the event queue and everything must be started from the beginning.
Remove the ConfigureNotify event handling and get the current parent size in the expose processing. This ignores the queued Configure Notify events the give a history of the parent size rather that the current parent window size.
So modifying the code you posted in the comments.
if (e.type == Expose) {
if (e.xexpose.count == 0) {
Window r;
int x,y;
unsigned int wd,ht, bw, dep;
XGetGeometry(d,w,&r,&x,&y,&wd,&ht,&bw,&dep);
width = wd - 20;
height = ht - 20;
XMoveResizeWindow (d, ww, 10, 10, width, height);
for (i=0;i<1000;i++) {
XFillRectangle(d, ww, DefaultGC(d, s), 20, 20, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), width-30, height-30, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), 20, height-30, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), width-30, 20, 10, 10);
}
}
}
Update: To fix the lack of expose events, add the following:
if (e.type == ConfigureNotify) {
{
while (XCheckTypedWindowEvent(d, w, ConfigureNotify, &e) == True);
width = e.xconfigure.width - 20;
height = e.xconfigure.height - 20;
XMoveResizeWindow (d, ww, 10, 10, width, height);
}
This will cause some more expose events. The XCheckTypedWindowEvent may not be necessary, it removes any all the ConfigureNotify events from the queue leaving the last one found in e.
Related
I have tried using this script down below and it does work however, after I get my cursor to another monitor I want to get back to the first monitor again, after I press the shortcut key after the first time. So basically if the cursor is on one monitor, move it to another, and after it is on the 2nd monitor, move it back to first one.
This is the script:
^Space::
CoordMode, Mouse, Screen ; This is needed to assure that you get your mouse coordinates related to the screen, not to the window
MouseGetPos, MouseX, MouseY
if( MouseX > 1920) ; 1920 is the Width of my monitor number 1
{
MouseMove, -A_ScreenWidth, 0, 0, R
}
else
{
MouseMove, A_ScreenWidth, 0, 0, R
}
return
You need to be explicit with the function, in this case, add the plus + expressly to add the current monitor's width:
^Space::
CoordMode, Mouse, Screen ; This is needed to assure that you get your mouse coordinates related to the screen, not to the window
MouseGetPos, MouseX, MouseY
if( MouseX > 1920) ; 1920 is the Width of my monitor number 1
{
MouseMove, -A_ScreenWidth, 0, 0, R
}
else
{
MouseMove, +A_ScreenWidth, 0, 0, R
}
return
which should work . . .
If not, or for more options (moving windows across different-sized monitors while scaling size and position) see fling https://www.autohotkey.com/board/topic/51956-flinging-windows-across-a-multi-monitor-system/
Quick and simple one this time. I have a subclassed tab control that handles WM_WINDOWPOSCHANGED to, when not SWP_NOSIZE, resize its content. It passes the WINDOWPOS lParam's cx and cy fields to TCM_ADJUSTRECT to get the content rect size.
I need to do this on command as well (after changing tabs, say). However, I can't just do a dummy resize to the same size; even with an explicit SetWindowPos(), real Windows seems to add SWP_NOSIZE itself if the size doesn't change. So I want to write the analogous code to my WM_WINDOWPOSCHANGED handler.
My question is: what coordinate system are the coordinates given to WM_WINDOWPOSCHANGED given in, parent coordinates or screen coordinates? GetWindowRect() returns screen coordinates, so I'd like to know if I need to convert the coordinates to get the same values that I would get in WM_WINDOWPOSCHANGED. The documentation for WM_WINDOWPOSCHANGED doesn't say; neither does the documentation for WINDOWPOS.
Thanks.
WINDOWPOS, GetWindowRect, GetCursorPos, etc. give screen coordinates. When you use SetWindowPos you have to supply coordinates in relation to parent. This is straight forward for main window and popup windows which use screen coordinates. For moving child windows, you can use ScreenToClient and ClientToScreen for conversion.
For example, this will find the coordinates of OK button in relation to top-left corner of dialog box:
RECT rcOK;
HWND hitem = ::GetDlgItem(m_hWnd, IDOK);
GetWndRect(rcOK, hitem, m_hWnd);
void GetWndRect(RECT &rect, HWND item, HWND parent)
{
::GetWindowRect(item, &rect);//screen coordinates of OK button
POINT offset{ 0 };
ClientToScreen(parent, &offset); //Top-left (0,0) of client area of dialog -> screen coordinates
rect.left -= offset.x;
rect.right -= offset.x;
rect.top -= offset.y;
rect.bottom -= offset.y;
//client coordinates of OK button in relation to Dialog's Top-Right
}
Now we can move up the OK button by 10px:
rc.top -= 10;
rc.bottom -= 10;
::SetWindowPos(hitem, 0, rc.left, rc.top, 0, 0, SWP_NOSIZE);
I am using GetSystemMetrics(SM_CXSIZEFRAME) for the width of the border, it works with the basic design, but not with aero, how can I improve it, so it works with aero?
I am using GetSystemMetrics(SM_CYCAPTION) for the height of the title bar but the value is too small for both, basic and aero design, what am I doing wrong here?
In unthemed Windows, GetSystemMetrics(SM_CYCAPTION) is the height of the text in the title bar; you need to add in the size of the frame and border padding (GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYEDGE) * 2).
For themed Windows (which is the default these days), GetThemeSysSize is most likely the function you're looking for; in particular, GetThemeSysSize(SM_CXBORDER) for the border width, and GetThemeSysSize(SM_CYSIZE) + GetThemeSysSize(SM_CXPADDEDBORDER) * 2 for the title bar.
I had a similar problem, where I needed to subtract the title bar height from the mouse Y to render a cursor in the window.
After looking around, and looking at functions like GetSystemMetrics, I ended up just using GetWindowRect and ClientToScreen.
I got the screen position of the client area using ClientToScreen with point 0,0.
Then subtracted that from the window top retrieved through GetWindowRect. Result is the distance from the top of the window to the inside of the window. Or the titlebar height.
int getWindowHeadSize()
{
RECT Rect;
GetWindowRect(hWnd, &Rect);
POINT point = { 0, 0 };
ClientToScreen(hWnd, &point);
return point.y - Rect.top + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYEDGE) * 2;
}
I am creating a WIN32 application. Is there a way I can change the window so that it can maximise to the left or right, as if you pressed win + right arrow or win + left arrow?
I've tried using the ShowWindow() method, but none of the parameters accept left or right maximisation. I've also tried using AdjustWindowRect() using the following code:
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, TRUE); // adjust the window
where wr is of type RECT, however this does not seem to change the window size or position.
Thanks!
'AdjustWindowRect' only "Calculates the required size of the window rectangle".
Use the MoveWindow function.
For example, to move the left border of the window to the left edge of the screen:
RECT rc;
GetWindowRect(hWnd, &rc);
MoveWindow(hWnd, 0, rc.top, rc.right, rc.bottom - rc.top, TRUE);
I am working on a GTK+ application that uses goocanvas to display a graph on screen. I am having problems coming up with a good way to implement drag scrolling.
Currently the app saves the coordinates where the user clicked and then in a "motion-notify" signal callback, does goo_canvas_scroll_to() to the new position. The problem is that drawing is somewhat slow, and with each pixel moved by the mouse, I get the callback invoked once. This makes the drawing lag behind when dragging the graph around.
Is there a good way to do drag scrolling, so it'd appear more smooth and I could skip some of the redraws?
I was able to get something like this working once by starting a 5ms timer when the user presses the mouse button. In the timer I check where the mouse is and decide which way to scroll, including faster scrolling the closer you are to the edge. The result was very smooth scrolling, at least that's what I remember. Here the guts of it, its gtkmm/c++, but you should be able to get the gist of it:
static const int HOT_AREA = 24;
// convert distance into scroll size. The larger the
// value, the faster the scrolling.
static int accel_fn(int dist) {
if (dist > HOT_AREA)
dist = HOT_AREA;
int dif = dist / (HOT_AREA/4);
if (dif <= 0) dif = 1;
return dif;
}
bool scrollerAddin::on_timeout() {
int ptr_x, ptr_y;
o_scroller->get_pointer(ptr_x, ptr_y);
int vp_width = o_scroller->get_width();
int vp_height = o_scroller->get_height();
if (o_scroller->get_hscrollbar_visible())
vp_height -= o_scroller->get_hscrollbar()->get_height();
if (o_scroller->get_vscrollbar_visible())
vp_width -= o_scroller->get_vscrollbar()->get_width();
if (ptr_x < HOT_AREA)
scroll_left(accel_fn(HOT_AREA-ptr_x));
else if (ptr_x > vp_width - HOT_AREA)
scroll_right(accel_fn(ptr_x - (vp_width - HOT_AREA)));
if (ptr_y < HOT_AREA)
scroll_up(accel_fn(HOT_AREA - ptr_y));
else if (ptr_y > vp_height - HOT_AREA)
scroll_down(accel_fn(ptr_y - (vp_height - HOT_AREA)));
return true;
}
The scroll functions merely adjust the appropriate Adjustment object by the argument.