How to stick window to left half part of screen? - x11

I am using xlib to set window to certain position using XMoveResizeWindow function
All works fine, but when I want to 'stick' my window to left part of screen, I get the wrong position and size: there is a space between window and left, top and bottom screen borders.
To find out 'right' coords & dimensions of window stuck to left manually, I have written a watcher program which continuously calls XGetGeometry and prints results to screen, so I got these results of a 'stuck' window:
X: -40
Y: 14
W: 2000
H: 2426
When I pass these values to XMoveResizeWindow function, I still get the wrong position.
I have extended my watcher program to print all available properties of the window to see which will be changed when I manually 'stick' the window, but nothing changed except max_width and max_height fields of WM_NORMAL_HINTS property.
If you have an idea what am I doing wrong, please let me know.

Related

Set the actual x, y position of a window

I'm writing a reparenting window manager, and some apps like Firefox misbehave when I move the window. For example, say I map firefox at (0, 0). Then I move it to (5, 5). When I open a menu, it will be offset by (5, 5), because it thinks the app's coordinates are (0, 0) but the actual frame window has been moved to (5, 5).
I do set the _NET_FRAME_EXTENTS property properly, but this still occurs. How do I tell the client application what it's actual x and y coordinates are, without configure_window'ing (and therefore actually moving it to some offset within a frame which breaks the whole thing) it?
Maybe also worth mentioning, after I move the window, if I resize it (and the frame, of course); it apparently works fine. so, i tried this strategy:
resize it to the height I want - 1 and the width I want
resize it to the height I want
I have no idea why this works, doing -1 on the width also works. in fact I can do any operation, just the result has to be that the window is resized, no matter how tiny, and firefox recieves the new coordinates. am I stuck with this hack or can I do better?
I can only guess. My guess is that you are not following ICCCM ยง 4.2.3:
If the window manager moves a top-level window without changing its size, the client will receive a synthetic ConfigureNotify event following the move that describes the new location in terms of the root coordinate space.
https://tronche.com/gui/x/icccm/sec-4.html#s-4.2.3
When you just move your frame windows, the client does not get a notification. Thus, these synthetic ConfigureNotify values are required.

Win32 Api WM_MOUSEMOVE moving mouse quick

I have created a small window by win api. This window is a child to the window of another thread.
I want allow user to move my window by moving mouse with presed right button. When I move my mouse in normal speed my window moves without problem. But when I move very quick some very strange messages recieved by window. For example,
P WM_MOUSEMOVE fwKeys:MK_BUTTON xPos:-32703 yPos:9
As you see the xPos drops down to a -32000. It happens almost instantly after I move my mouse quick. I have no idea how windows can send me such a message.
Why that message could be sended and how to fix it?
I am using a SetCaption function, so my window recievs messages even if mouse stays outside.
Upd. Solved. The problem was in my inherent maths. Getting hi and lowword from lParam wasn't proper.
I had the same issue while implementing dragging support, making rapid small circles in the middle of the screen with the mouse while left button is pressed, generates some out of range positions (like -32000 or -64000, despite proper handling of the lParam coordinates conversion). This looked like a bug to me, so I worked around it by clipping x and y to current screen size in pixels for the max values and allowing negative values down to a negative screen size box.
This is a code extract for better comprehension (written in Red/System):
WM_MOUSEMOVE [
lParam: msg/lParam
x: GET_X_LPARAM(lParam)
y: GET_Y_LPARAM(lParam)
if any [
x < (0 - screen-size-x)
y < (0 - screen-size-y)
x > screen-size-x
y > screen-size-y
][
return 0 ;-- ignore this event
]
...
]
That solved it for me.

How do I change the viewport of a window in win32?

I have a window with child windows inside in it. The child windows take up about 1000 pixels of vertical space. However, our users don't always have 1000 pixels of vertical space available - they might have as little as 500 or 600 pixels.
I want to be able to display this window at a size of 500 pixels high, and have the user "scroll" up and down the window to see the full contents. The window should always be 500 pixels high, but the view within it should change.
Assume I can add a scroll bar somewhere so the user can choose which part of the window he wants to see. Windows will normally paint the window contents from height 0 to height 500; how do I tell it instead to "paint from height 250 to height 750", for example?
I know that I can set the viewport with functions like SetViewportOrgEx etc, but those functions require a device context - when do I call them if I want them to be "permanent"? Do I call them when I get the WM_PAINT message from windows? Or at some other time? And which functions from that family do I want to use?
Edit to add: I don't want to actually change the position of the child windows - they should stay at the same position, and the only thing that should change is the view into the window.
Thanks.
If (when you get messages about the scroll bars changing) you call ScrollWindowEx with the SW_SCROLLCHILDREN flag, the child windows should be told to scroll along with everything else. This ought to put them in the right position.

win32: detect if start menu is auto-hidden?

I want to position a window at the bottom of the screen. If the start menu is present, I want it to lie along the top of the start menu. If it is not (or it is auto-hidden), I still want it to be in the same position as it would be if the start menu was there, meaning there will be a gap of a few pixels.
Currently I get the monitor work area, position the window at the bottom, and always offset by 20 pixels or so. If the start menu isn't there, this works well. If it is, however, the work area also shrinks (as it should), and I end up double-offsetting.
How would I fix the issue?
To get the work area of the screen not obscured by the system taskbar or by application desktop toolbars, you can use SystemParametersInfo() with SPI_GETWORKAREA as uiAction parameter. The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in virtual screen coordinates. For example:
RECT rectWorkArea;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rectWorkArea, 0);
As you said in the comment, to get the bounding rectangle of the taskbar, we can call SHAppBarMessage(ABM_GETTASKBARPOS, ...)
To determine the position of the taskbar (whether it is currently at the bottom, top, left, or right of the screen), you could use the following calculation:
type
TTaskBarPos = (_TOP, _BOTTOM, _LEFT, _RIGHT);
var
iScrW, iScrH: Longint;
iScrW := GetSystemMetrics(SM_CXSCREEN);
iScrH := GetSystemMetrics(SM_CXSCREEN);
if (rectTaskbar.Top > iScrH div 2) and (rectTaskbar.Right >= iScrW) then
Result := _BOTTOM
else if (rectTaskbar.Top < iScrH div 2) and (rectTaskbar.Bottom <= iScrW div 2) then
Result := _TOP
else if (rectTaskbar.Left < iScrW div 2) and (rectTaskbar.Top <= 0) then
Result := _LEFT
else
Result := _RIGHT;
They should be enough to solve your current problem. However, if you need to know (for another reason) the current taskbar settings of the autohide and always-on-top states, you can use SHAppBarMessage(ABM_GETSTATE, ...).
If you need to be notified that that the taskbar's autohide or always-on-top state has changed, you have to intercept ABN_STATECHANGE message.
Are you are using or have access to .NET in your project?
If so, you can use the Screen.PrimaryScreen.WorkingArea.Height property to determine the bottom of the screen excluding the task bar.
You can also grab the total screen height by getting the Screen.PrimaryScreen.Bounds.Height property (which includes the task bar in the total height value).
Comparing these values, if they're the same, the task bar isn't present. Otherwise, the task bar is and you can adjust accordingly.

AutoHotkey MouseMove not centering properly

I'm running the below code and I expect the mouse to move to the center of the currently active window when I hit comma.....instead it is moving to different points on the screen, depending on where the window is on the screen. It only centers the mouse properly when the window is positioned at the top left (x=0, y=0).
#NoEnv
SendMode Input
#WinActivateForce
Sysget, Mon2, Monitor, 2
,::
WinGetActiveStats, Title, Width, Height, X, Y
{
MsgBox, The active window "%Title%" is %Width% wide`, %Height% tall`, and positioned at %X%`,%Y%.
;center_x:=X+(Width*.5)
;center_y:=Y+(Height*.5)
MouseMove, X+(Width*.5), Y+(Height*.5), 90
}
Return
Check out CoordMode in the documentation.
Sets coordinate mode for various commands to be relative to either the
active window or the screen.
CoordMode, ToolTip|Pixel|Mouse|Caret|Menu [, Screen|Window|Client]
The default CoordMode is Screen which is why you get two different locations. Set the CoordMode to Window to assure that your mouse centering works on the active window.
You can set it for the entire script by calling it during the Auto-Execute section of the script.
The following script will move mouse to Active Window on dual screen system.
I could not get it to work until I put in the sleep line, WinGetPos was getting info before the window had moved.
~#+right::
~#+left::
Sleep,1000
WinGetPos, X, Y, width, height, A
center_x:=width/2
center_y:=height/2
MouseMove,center_x,center_y,
return
I would be sure that Width and Height are the actual dimensions of the window and not the screen resolution. Then check X and Y to ensure they're the actual top-left corner of the active window.
If the width and height are not from the actual window, i.e. the screen size, then this is expected behaivor. Perhaps you could show us the calling function to get a better idea of where those parameters are coming from.
the problem was that MousMove uses the coordinates of the window by default, so I changed the MouseMove line to the following:
MouseMove, Width*.5, Height*.5
All is good.
Tried it all nothing works. The trick is to use DllCall("SetCursorPos", int, x, int, y).
Here is the code to move mouse to center of window. Works on multi-montior and non-fullscreen windows.
MoveMouseInCenterOfActiveWindow:
CoordMode,Mouse,Screen
WinGetPos, winTopL_x, winTopL_y, width, height, A
;MouseMove, X, Y, 0 ; does not work with multi-monitor (always off)
winCenter_x := winTopL_x + width/2
winCenter_y := winTopL_y + height/2
DllCall("SetCursorPos", int, winCenter_x, int, winCenter_y)
Tooltip winTopL_x:%winTopL_x% winTopL_y:%winTopL_y% winCenter_x:%winCenter_x% winCenter_y:%winCenter_y%
return

Resources