From: Andrea Faulds <ajf@ajf.me> Before this commit: - SPI_SETWORKAREA was only affecting the result of SPI_GETWORKAREA, which meant that, for example, it didn't affect the code in dlls/win32u/window.c which determines the size of a maximized window. - SPI_SETWORKAREA was only affecting the current process, rather than all processes on the same desktop. The multiprocess aspect is impractical to test with WINE's automated tests, but manual tests with a simple program found that SPI_SETWORKAREA does in fact affect the maximized size for itself and other processes on Windows 2000 and XP. --- dlls/win32u/sysparams.c | 90 ++++++++++++++++++++++------------ include/wine/server_protocol.h | 19 ++++++- server/protocol.def | 7 +++ server/queue.c | 18 +++++++ server/request_handlers.h | 4 ++ server/request_trace.h | 9 ++++ server/winstation.c | 4 ++ 7 files changed, 118 insertions(+), 33 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index fa22d6294c0..4301bcd3500 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -294,7 +294,6 @@ union sysparam_all_entry static const struct ratio no_dpi; UINT system_dpi; -static RECT work_area; static DWORD process_layout = ~0u; static HDC display_dc; @@ -4697,6 +4696,27 @@ static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info, struct ratio d monitor_get_info( monitor, info, dpi ); unlock_display_devices(); + /* the primary monitor's work area can be updated by another process */ + if (is_monitor_primary( monitor )) + { + struct object_lock lock = OBJECT_LOCK_INIT; + const desktop_shm_t *desktop_shm; + NTSTATUS status; + struct rectangle shared_rect = { 0 }; + while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) + shared_rect = desktop_shm->work_area; + TRACE( "got shared work area rect: %d %d %d %d\n", + shared_rect.left, shared_rect.top, shared_rect.right, shared_rect.bottom); + if (!(shared_rect.left == 0 && shared_rect.right == 0 && + shared_rect.top == 0 && shared_rect.bottom == 0)) + { + info->rcWork = map_monitor_rect( + monitor, wine_server_get_rect( shared_rect ), + dpi, MDT_DEFAULT, no_dpi, MDT_RAW_DPI + ); + } + } + TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags, wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork)); return TRUE; @@ -5728,16 +5748,6 @@ static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 ); static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 ); static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 ); -/* System parameter indexes */ -enum spi_index -{ - SPI_SETWORKAREA_IDX, - SPI_INDEX_COUNT -}; - -/* indicators whether system parameter value is loaded */ -static char spi_loaded[SPI_INDEX_COUNT]; - static struct sysparam_rgb_entry system_colors[] = { #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) } @@ -6122,7 +6132,6 @@ BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT w break BOOL ret = user_driver->pSystemParametersInfo( action, val, ptr, winini ); - unsigned spi_idx = 0; if (!ret) switch (action) { @@ -6362,41 +6371,58 @@ BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT w } case SPI_SETWORKAREA: { + struct monitor *monitor; + struct ratio dpi = get_thread_dpi(); + RECT nodpi_rcWork = { 0 }; + if (!ptr) return FALSE; - spi_idx = SPI_SETWORKAREA_IDX; - work_area = *(RECT*)ptr; - spi_loaded[spi_idx] = TRUE; + + if (!lock_display_devices( FALSE )) return FALSE; + + LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) + { + if (!is_monitor_primary( monitor )) continue; + nodpi_rcWork = map_monitor_rect( monitor, *(RECT *)ptr, dpi, MDT_DEFAULT, no_dpi, MDT_RAW_DPI ); + break; + } + + unlock_display_devices(); + + /* Update the work area for all WINE processes on this desktop. */ + SERVER_START_REQ( set_work_area ) + { + req->work_area = wine_server_rectangle( nodpi_rcWork ); + TRACE("SERVER_START_REQ( set_work_area ): %d %d %d %d\n", + nodpi_rcWork.left, nodpi_rcWork.top, nodpi_rcWork.right, nodpi_rcWork.bottom); + wine_server_call( req ); + } + SERVER_END_REQ; + ret = TRUE; break; } case SPI_GETWORKAREA: { + struct monitor *monitor; MONITORINFO info = {.cbSize = sizeof(info)}; struct ratio dpi = get_thread_dpi(); if (!ptr) return FALSE; - spi_idx = SPI_SETWORKAREA_IDX; - if (!spi_loaded[spi_idx]) - { - struct monitor *monitor; + if (!lock_display_devices( FALSE )) return FALSE; - if (!lock_display_devices( FALSE )) return FALSE; + LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) + { + if (!is_monitor_primary( monitor )) continue; + monitor_get_info( monitor, &info, dpi ); + *(RECT *)ptr = info.rcWork; + break; + } - LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) - { - if (!is_monitor_primary( monitor )) continue; - monitor_get_info( monitor, &info, dpi ); - work_area = info.rcWork; - break; - } + unlock_display_devices(); - unlock_display_devices(); - spi_loaded[spi_idx] = TRUE; - } - *(RECT *)ptr = work_area; ret = TRUE; - TRACE("work area %s\n", wine_dbgstr_rect( &work_area )); + TRACE("work area %s\n", wine_dbgstr_rect( (RECT *)ptr )); break; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2f04955a486..b995343d642 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -998,6 +998,7 @@ typedef volatile struct unsigned int flags; struct shared_cursor cursor; unsigned char keystate[256]; + struct rectangle work_area; unsigned __int64 monitor_serial; unsigned __int64 keystate_serial; } desktop_shm_t; @@ -5820,6 +5821,19 @@ struct get_cursor_history_reply +struct set_work_area_request +{ + struct request_header __header; + struct rectangle work_area; + char __pad_28[4]; +}; +struct set_work_area_reply +{ + struct reply_header __header; +}; + + + struct get_rawinput_buffer_request { struct request_header __header; @@ -6521,6 +6535,7 @@ enum request REQ_free_user_handle, REQ_set_cursor, REQ_get_cursor_history, + REQ_set_work_area, REQ_get_rawinput_buffer, REQ_update_rawinput_devices, REQ_create_job, @@ -6836,6 +6851,7 @@ union generic_request struct free_user_handle_request free_user_handle_request; struct set_cursor_request set_cursor_request; struct get_cursor_history_request get_cursor_history_request; + struct set_work_area_request set_work_area_request; struct get_rawinput_buffer_request get_rawinput_buffer_request; struct update_rawinput_devices_request update_rawinput_devices_request; struct create_job_request create_job_request; @@ -7149,6 +7165,7 @@ union generic_reply struct free_user_handle_reply free_user_handle_reply; struct set_cursor_reply set_cursor_reply; struct get_cursor_history_reply get_cursor_history_reply; + struct set_work_area_reply set_work_area_reply; struct get_rawinput_buffer_reply get_rawinput_buffer_reply; struct update_rawinput_devices_reply update_rawinput_devices_reply; struct create_job_reply create_job_reply; @@ -7177,6 +7194,6 @@ union generic_reply struct alpc_create_port_reply alpc_create_port_reply; }; -#define SERVER_PROTOCOL_VERSION 959 +#define SERVER_PROTOCOL_VERSION 960 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 118bafd9c9b..24db39980f5 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1014,6 +1014,7 @@ typedef volatile struct unsigned int flags; /* desktop flags */ struct shared_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + struct rectangle work_area; /* work area rect for primary monitor (if set with SPI_SETWORKAREA) */ unsigned __int64 monitor_serial; /* winstation monitor update counter */ unsigned __int64 keystate_serial; /* keystate update counter */ } desktop_shm_t; @@ -4082,6 +4083,12 @@ struct handle_info @END +/* Set the work area rectangle for the primary monitor */ +@REQ(set_work_area) + struct rectangle work_area; /* work area rectangle to set */ +@END + + /* Batch read rawinput message data */ @REQ(get_rawinput_buffer) data_size_t header_size; /* size of RAWINPUTHEADER structure */ diff --git a/server/queue.c b/server/queue.c index 3d8ae3f96dd..7df45709fcf 100644 --- a/server/queue.c +++ b/server/queue.c @@ -4040,6 +4040,24 @@ DECL_HANDLER(get_cursor_history) pos[i] = cursor_history[(i + cursor_history_latest) % ARRAY_SIZE(cursor_history)]; } +/* Set the work area rectangle for the primary monitor */ +DECL_HANDLER(set_work_area) +{ + struct msg_queue *queue = get_current_queue(); + struct desktop *desktop; + desktop_shm_t *desktop_shm; + + if (!queue) return; + desktop = queue->input->desktop; + desktop_shm = desktop->shared; + + SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) + { + shared->work_area = req->work_area; + } + SHARED_WRITE_END; +} + DECL_HANDLER(get_rawinput_buffer) { const size_t align = is_machine_64bit( current->process->machine ) ? 7 : 3; diff --git a/server/request_handlers.h b/server/request_handlers.h index 3372c6c92db..b0b6c615826 100644 --- a/server/request_handlers.h +++ b/server/request_handlers.h @@ -289,6 +289,7 @@ DECL_HANDLER(alloc_user_handle); DECL_HANDLER(free_user_handle); DECL_HANDLER(set_cursor); DECL_HANDLER(get_cursor_history); +DECL_HANDLER(set_work_area); DECL_HANDLER(get_rawinput_buffer); DECL_HANDLER(update_rawinput_devices); DECL_HANDLER(create_job); @@ -601,6 +602,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_free_user_handle, (req_handler)req_set_cursor, (req_handler)req_get_cursor_history, + (req_handler)req_set_work_area, (req_handler)req_get_rawinput_buffer, (req_handler)req_update_rawinput_devices, (req_handler)req_create_job, @@ -2261,6 +2263,8 @@ C_ASSERT( offsetof(struct set_cursor_reply, last_change) == 48 ); C_ASSERT( sizeof(struct set_cursor_reply) == 56 ); C_ASSERT( sizeof(struct get_cursor_history_request) == 16 ); C_ASSERT( sizeof(struct get_cursor_history_reply) == 8 ); +C_ASSERT( offsetof(struct set_work_area_request, work_area) == 12 ); +C_ASSERT( sizeof(struct set_work_area_request) == 32 ); C_ASSERT( offsetof(struct get_rawinput_buffer_request, header_size) == 12 ); C_ASSERT( offsetof(struct get_rawinput_buffer_request, read_data) == 16 ); C_ASSERT( sizeof(struct get_rawinput_buffer_request) == 24 ); diff --git a/server/request_trace.h b/server/request_trace.h index eed94a179b8..c10129aaefe 100644 --- a/server/request_trace.h +++ b/server/request_trace.h @@ -3266,6 +3266,11 @@ static void dump_get_cursor_history_reply( const struct get_cursor_history_reply dump_varargs_cursor_positions( " history=", cur_size ); } +static void dump_set_work_area_request( const struct set_work_area_request *req ) +{ + dump_rectangle( " work_area=", &req->work_area ); +} + static void dump_get_rawinput_buffer_request( const struct get_rawinput_buffer_request *req ) { fprintf( stderr, " header_size=%u", req->header_size ); @@ -3821,6 +3826,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = (dump_func)dump_free_user_handle_request, (dump_func)dump_set_cursor_request, (dump_func)dump_get_cursor_history_request, + (dump_func)dump_set_work_area_request, (dump_func)dump_get_rawinput_buffer_request, (dump_func)dump_update_rawinput_devices_request, (dump_func)dump_create_job_request, @@ -4133,6 +4139,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = NULL, (dump_func)dump_set_cursor_reply, (dump_func)dump_get_cursor_history_reply, + NULL, (dump_func)dump_get_rawinput_buffer_reply, NULL, (dump_func)dump_create_job_reply, @@ -4445,6 +4452,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = "free_user_handle", "set_cursor", "get_cursor_history", + "set_work_area", "get_rawinput_buffer", "update_rawinput_devices", "create_job", @@ -4550,6 +4558,7 @@ static const struct { "INVALID_PIPE_STATE", STATUS_INVALID_PIPE_STATE }, { "INVALID_READ_MODE", STATUS_INVALID_READ_MODE }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, + { "INVALID_STATE_TRANSITION", STATUS_INVALID_STATE_TRANSITION }, { "INVALID_USER_BUFFER", STATUS_INVALID_USER_BUFFER }, { "IO_REPARSE_DATA_INVALID", STATUS_IO_REPARSE_DATA_INVALID }, { "IO_REPARSE_TAG_INVALID", STATUS_IO_REPARSE_TAG_INVALID }, diff --git a/server/winstation.c b/server/winstation.c index d27adc3ecb4..9b3fad5f0fd 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -299,6 +299,10 @@ static bool desktop_init( struct object *obj, const void *init_data ) shared->cursor.clip.top = 0; shared->cursor.clip.right = 0; shared->cursor.clip.bottom = 0; + shared->work_area.left = 0; + shared->work_area.top = 0; + shared->work_area.right = 0; + shared->work_area.bottom = 0; memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); shared->keystate_serial = 1; shared->monitor_serial = winstation->monitor_serial; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11699