wfreerdp: scrollbars, aspect ratio smartsizing

This commit is contained in:
Benoit LeBlanc 2013-04-26 15:46:36 -04:00
parent b91a7cd3a8
commit 391d238f1a
4 changed files with 343 additions and 28 deletions

View File

@ -150,6 +150,41 @@ static int wf_event_process_WM_MOUSEWHEEL(wfInfo* wfi, HWND hWnd, UINT Msg, WPAR
return 0;
}
void wf_sizing(wfInfo* wfi, WPARAM wParam, LPARAM lParam)
{
// Holding the CTRL key down while resizing the window will force the desktop aspect ratio.
LPRECT rect;
if (wfi->instance->settings->SmartSizing && (GetAsyncKeyState(VK_CONTROL) & 0x8000))
{
rect = (LPRECT) wParam;
switch(lParam)
{
case WMSZ_LEFT:
case WMSZ_RIGHT:
case WMSZ_BOTTOMRIGHT:
// Adjust height
rect->bottom = rect->top + wfi->height * (rect->right - rect->left) / wfi->instance->settings->DesktopWidth;
break;
case WMSZ_TOP:
case WMSZ_BOTTOM:
case WMSZ_TOPRIGHT:
// Adjust width
rect->right = rect->left + wfi->width * (rect->bottom - rect->top) / wfi->instance->settings->DesktopHeight;
break;
case WMSZ_BOTTOMLEFT:
case WMSZ_TOPLEFT:
// adjust width
rect->left = rect->right - (wfi->width * (rect->bottom - rect->top) / wfi->instance->settings->DesktopHeight);
break;
}
}
}
LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
@ -162,6 +197,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
RECT windowRect, clientRect;
MINMAXINFO *minmax;
SCROLLINFO si;
processed = TRUE;
ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA);
@ -176,42 +212,54 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
case WM_MOVE:
if (!wfi->disablewindowtracking)
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
int x = (int)(short) LOWORD(lParam);
int y = (int)(short) HIWORD(lParam);
((wfContext*) wfi->instance->context)->wfi->client_x = x;
((wfContext*) wfi->instance->context)->wfi->client_y = y;
}
break;
case WM_GETMINMAXINFO:
// Set maximum window size for resizing
minmax = (MINMAXINFO*) lParam;
wf_update_canvas_diff(wfi);
if (!wfi->fullscreen)
if (wfi->instance->settings->SmartSizing)
{
// add window decoration
minmax->ptMaxTrackSize.x = wfi->width + wfi->diff.x;
minmax->ptMaxTrackSize.y = wfi->height + wfi->diff.y;
processed = FALSE;
}
break;
case WM_SIZE:
else
{
int dwStyle = GetWindowLongPtr(wfi->hwnd, GWL_STYLE);
int width = LOWORD(lParam);
int height = HIWORD(lParam);
// Set maximum window size for resizing
minmax = (MINMAXINFO*) lParam;
wf_update_canvas_diff(wfi);
if (!wfi->fullscreen)
{
((wfContext*) wfi->instance->context)->wfi->client_width = width;
((wfContext*) wfi->instance->context)->wfi->client_height = height;
// add window decoration
minmax->ptMaxTrackSize.x = wfi->width + wfi->diff.x;
minmax->ptMaxTrackSize.y = wfi->height + wfi->diff.y;
}
}
break;
case WM_SIZING:
wf_sizing(wfi, lParam, wParam);
break;
case WM_SIZE:
if (!wfi->fullscreen)
{
GetWindowRect(wfi->hwnd, &windowRect);
wfi->client_width = LOWORD(lParam);
wfi->client_height = HIWORD(lParam);
wfi->client_x = windowRect.left;
wfi->client_y = windowRect.top;
}
wf_size_scrollbars(wfi, LOWORD(lParam), HIWORD(lParam));
break;
case WM_EXITSIZEMOVE:
wf_size_scrollbars(wfi, wfi->client_width, wfi->client_height);
break;
case WM_ERASEBKGND:
/* Say we handled it - prevents flickering */
return (LRESULT) 1;
@ -224,7 +272,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
w = ps.rcPaint.right - ps.rcPaint.left + 1;
h = ps.rcPaint.bottom - ps.rcPaint.top + 1;
wf_scale_blt(wfi, hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x, y - wfi->offset_y, SRCCOPY);
wf_scale_blt(wfi, hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x + wfi->xCurrentScroll, y - wfi->offset_y + wfi->yCurrentScroll, SRCCOPY);
EndPaint(hWnd, &ps);
break;
@ -260,6 +308,151 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
DefWindowProc(hWnd, Msg, wParam, lParam);
break;
case WM_HSCROLL:
{
int xDelta; // xDelta = new_pos - current_pos
int xNewPos; // new position
int yDelta = 0;
switch (LOWORD(wParam))
{
// User clicked the scroll bar shaft left of the scroll box.
case SB_PAGEUP:
xNewPos = wfi->xCurrentScroll - 50;
break;
// User clicked the scroll bar shaft right of the scroll box.
case SB_PAGEDOWN:
xNewPos = wfi->xCurrentScroll + 50;
break;
// User clicked the left arrow.
case SB_LINEUP:
xNewPos = wfi->xCurrentScroll - 5;
break;
// User clicked the right arrow.
case SB_LINEDOWN:
xNewPos = wfi->xCurrentScroll + 5;
break;
// User dragged the scroll box.
case SB_THUMBPOSITION:
xNewPos = HIWORD(wParam);
// user is dragging the scrollbar
case SB_THUMBTRACK :
xNewPos = HIWORD(wParam);
break;
default:
xNewPos = wfi->xCurrentScroll;
}
// New position must be between 0 and the screen width.
xNewPos = MAX(0, xNewPos);
xNewPos = MIN(wfi->xMaxScroll, xNewPos);
// If the current position does not change, do not scroll.
if (xNewPos == wfi->xCurrentScroll)
break;
// Determine the amount scrolled (in pixels).
xDelta = xNewPos - wfi->xCurrentScroll;
// Reset the current scroll position.
wfi->xCurrentScroll = xNewPos;
// Scroll the window. (The system repaints most of the
// client area when ScrollWindowEx is called; however, it is
// necessary to call UpdateWindow in order to repaint the
// rectangle of pixels that were invalidated.)
ScrollWindowEx(wfi->hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
SW_INVALIDATE);
UpdateWindow(wfi->hwnd);
// Reset the scroll bar.
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = wfi->xCurrentScroll;
SetScrollInfo(wfi->hwnd, SB_HORZ, &si, TRUE);
}
break;
case WM_VSCROLL:
{
int xDelta = 0;
int yDelta; // yDelta = new_pos - current_pos
int yNewPos; // new position
switch (LOWORD(wParam))
{
// User clicked the scroll bar shaft above the scroll box.
case SB_PAGEUP:
yNewPos = wfi->yCurrentScroll - 50;
break;
// User clicked the scroll bar shaft below the scroll box.
case SB_PAGEDOWN:
yNewPos = wfi->yCurrentScroll + 50;
break;
// User clicked the top arrow.
case SB_LINEUP:
yNewPos = wfi->yCurrentScroll - 5;
break;
// User clicked the bottom arrow.
case SB_LINEDOWN:
yNewPos = wfi->yCurrentScroll + 5;
break;
// User dragged the scroll box.
case SB_THUMBPOSITION:
yNewPos = HIWORD(wParam);
break;
// user is dragging the scrollbar
case SB_THUMBTRACK :
yNewPos = HIWORD(wParam);
break;
default:
yNewPos = wfi->yCurrentScroll;
}
// New position must be between 0 and the screen height.
yNewPos = MAX(0, yNewPos);
yNewPos = MIN(wfi->yMaxScroll, yNewPos);
// If the current position does not change, do not scroll.
if (yNewPos == wfi->yCurrentScroll)
break;
// Determine the amount scrolled (in pixels).
yDelta = yNewPos - wfi->yCurrentScroll;
// Reset the current scroll position.
wfi->yCurrentScroll = yNewPos;
// Scroll the window. (The system repaints most of the
// client area when ScrollWindowEx is called; however, it is
// necessary to call UpdateWindow in order to repaint the
// rectangle of pixels that were invalidated.)
ScrollWindowEx(wfi->hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
SW_INVALIDATE);
UpdateWindow(wfi->hwnd);
// Reset the scroll bar.
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = wfi->yCurrentScroll;
SetScrollInfo(wfi->hwnd, SB_VERT, &si, TRUE);
}
break;
default:
processed = FALSE;
break;
@ -358,8 +551,8 @@ void wf_scale_mouse_event(wfInfo* wfi, rdpInput* input, UINT16 flags, UINT16 x,
dw = wfi->instance->settings->DesktopWidth;
dh = wfi->instance->settings->DesktopHeight;
if ((ww >= dw) && (wh >= dh))
input->MouseEvent(input, flags, x, y);
if (!wfi->instance->settings->SmartSizing || (ww >= dw) && (wh >= dh))
input->MouseEvent(input, flags, x + wfi->xCurrentScroll, y + wfi->yCurrentScroll);
else
input->MouseEvent(input, flags, MAX(x, x * dw / ww), MAX(y, y * dh / wh));
input->MouseEvent(input, flags, MAX(x, x * dw / ww) + wfi->xCurrentScroll, MAX(y, y * dh / wh) + wfi->yCurrentScroll);
}

View File

@ -195,6 +195,11 @@ void wf_scale_rect(wfInfo* wfi, RECT* source)
source->left = MIN(source->left - 2, MAX(0, source->left * ww / dw - 2));
source->right = MIN(source->right + 2, MAX(0, source->right * ww / dw + 2));
}
source->bottom -= wfi->yCurrentScroll;
source->top -= wfi->yCurrentScroll;
source->left -= wfi->xCurrentScroll;
source->right -= wfi->xCurrentScroll;
}
void wf_invalidate_region(wfInfo* wfi, int x, int y, int width, int height)
@ -303,11 +308,12 @@ void wf_resize_window(wfInfo* wfi)
if (!wfi->client_y)
wfi->client_y = 10;
wf_update_canvas_diff(wfi);
/* Now resize to get full canvas size and room for caption and borders */
SetWindowPos(wfi->hwnd, HWND_TOP, wfi->client_x, wfi->client_y, wfi->client_width + wfi->diff.x, wfi->client_height + wfi->diff.y, SWP_FRAMECHANGED);
SetWindowPos(wfi->hwnd, HWND_TOP, wfi->client_x, wfi->client_y, wfi->client_width + wfi->diff.x, wfi->client_height + wfi->diff.y, 0 /*SWP_FRAMECHANGED*/);
//wf_size_scrollbars(wfi, wfi->client_width, wfi->client_height);
}
wf_update_offset(wfi);
}

View File

@ -430,7 +430,7 @@ BOOL wf_post_connect(freerdp* instance)
UpdateWindow(wfi->hwnd);
if (wfi->sw_gdi)
{
{
instance->update->BeginPaint = wf_sw_begin_paint;
instance->update->EndPaint = wf_sw_end_paint;
instance->update->DesktopResize = wf_sw_desktop_resize;
@ -1023,4 +1023,103 @@ int freerdp_client_save_settings_to_rdp_file(wfInfo* cfi, char* filename)
}
return 0;
}
void wf_size_scrollbars(wfInfo* wfi, int client_width, int client_height)
{
if (wfi->disablewindowtracking == TRUE)
{
return;
}
// prevent infinite message loop
wfi->disablewindowtracking = TRUE;
if (wfi->instance->settings->SmartSizing && (wfi->xScrollVisible || wfi->yScrollVisible))
{
wfi->xScrollVisible = FALSE;
wfi->yScrollVisible = FALSE;
ShowScrollBar(wfi->hwnd, SB_BOTH, FALSE);
}
else
{
SCROLLINFO si;
BOOL horiz = wfi->xScrollVisible;
BOOL vert = wfi->yScrollVisible;;
if (!horiz && client_width < wfi->instance->settings->DesktopWidth)
{
horiz = TRUE;
}
else if (horiz && client_width >= wfi->instance->settings->DesktopWidth/* - GetSystemMetrics(SM_CXVSCROLL)*/)
{
horiz = FALSE;
}
if (!vert && client_height < wfi->instance->settings->DesktopHeight)
{
vert = TRUE;
}
else if (vert && client_height >= wfi->instance->settings->DesktopHeight/* - GetSystemMetrics(SM_CYHSCROLL)*/)
{
vert = FALSE;
}
if (horiz == vert && (horiz != wfi->xScrollVisible && vert != wfi->yScrollVisible))
{
ShowScrollBar(wfi->hwnd, SB_BOTH, horiz);
wfi->xScrollVisible = horiz;
wfi->yScrollVisible = vert;
}
if (horiz != wfi->xScrollVisible)
{
ShowScrollBar(wfi->hwnd, SB_HORZ, horiz);
wfi->xScrollVisible = horiz;
}
if (vert != wfi->yScrollVisible)
{
ShowScrollBar(wfi->hwnd, SB_VERT, vert);
wfi->yScrollVisible = vert;
}
if (horiz)
{
// The horizontal scrolling range is defined by
// (bitmap_width) - (client_width). The current horizontal
// scroll value remains within the horizontal scrolling range.
wfi->xMaxScroll = MAX(wfi->instance->settings->DesktopWidth - client_width, 0);
wfi->xCurrentScroll = MIN(wfi->xCurrentScroll, wfi->xMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = wfi->xMinScroll;
si.nMax = wfi->instance->settings->DesktopWidth;
si.nPage = client_width;
si.nPos = wfi->xCurrentScroll;
SetScrollInfo(wfi->hwnd, SB_HORZ, &si, TRUE);
}
if (vert)
{
// The vertical scrolling range is defined by
// (bitmap_height) - (client_height). The current vertical
// scroll value remains within the vertical scrolling range.
wfi->yMaxScroll = MAX(wfi->instance->settings->DesktopHeight - client_height, 0);
wfi->yCurrentScroll = MIN(wfi->yCurrentScroll, wfi->yMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = wfi->yMinScroll;
si.nMax = wfi->instance->settings->DesktopHeight;
si.nPage = client_height;
si.nPos = wfi->yCurrentScroll;
SetScrollInfo(wfi->hwnd, SB_VERT, &si, TRUE);
}
wfi->disablewindowtracking = FALSE;
wf_update_canvas_diff(wfi);
}
}

View File

@ -48,6 +48,9 @@ extern "C" {
#define CALLBACK_TYPE_CONNECTED 0x02
#define CALLBACK_TYPE_DISCONNECTED 0x03
// System menu constants
#define SMARTSIZING_SYS_MENU_ID 1000
struct wf_bitmap
{
rdpBitmap _bitmap;
@ -132,6 +135,19 @@ struct wf_info
// Keep track of window size and position, disable when in fullscreen mode.
BOOL disablewindowtracking;
// These variables are required for horizontal scrolling.
BOOL updating_scrollbars;
BOOL xScrollVisible;
int xMinScroll; // minimum horizontal scroll value
int xCurrentScroll; // current horizontal scroll value
int xMaxScroll; // maximum horizontal scroll value
// These variables are required for vertical scrolling.
BOOL yScrollVisible;
int yMinScroll; // minimum vertical scroll value
int yCurrentScroll; // current vertical scroll value
int yMaxScroll; // maximum vertical scroll value
};
/**
@ -141,6 +157,7 @@ struct wf_info
#define cfInfo wfInfo
void wf_on_param_change(freerdp* instance, int id);
void wf_size_scrollbars(wfInfo* wfi, int client_width, int client_height);
FREERDP_API int freerdp_client_global_init();
FREERDP_API int freerdp_client_global_uninit();
@ -162,7 +179,7 @@ FREERDP_API rdpSettings* freerdp_client_get_settings(wfInfo* wfi);
FREERDP_API int freerdp_client_load_settings_from_rdp_file(wfInfo* cfi, char* filename);
FREERDP_API int freerdp_client_save_settings_to_rdp_file(wfInfo* cfi, char* filename);
#ifdef __cplusplus
}
#endif