mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2025-02-21 11:21:32 +00:00
improved multi-monitor support
- /monitorlist - the monitor list gets updated during video restarts and by /monitorlist - Linux > r_monitor is now 0-based and monitors are sorted top-to-bottom, left-to-right - Windows > the Windows + shift + left/right arrow key shortcuts should be ok to use
This commit is contained in:
parent
e42c05dfc8
commit
3305c6f515
9 changed files with 142 additions and 52 deletions
|
@ -1,5 +1,5 @@
|
|||
|
||||
DD Mmm 18 - 1.51
|
||||
DD Mmm 19 - 1.51
|
||||
|
||||
add: demo recording status query extension for CPMA 1.52+
|
||||
|
||||
|
@ -16,6 +16,12 @@ add: /toggle can now accept a value sequence (2 or more entries) to loop through
|
|||
if the cvar's current value is in the sequence and not in the last spot, the next one is used
|
||||
otherwise, the first value in the sequence is used
|
||||
|
||||
chg: multi-monitor support improvements
|
||||
add: /monitorlist will print all detected monitors and the indices to use with r_monitor
|
||||
chg: the monitor list now gets updated during video restarts and calls to /monitorlist
|
||||
chg: Linux | r_monitor is a 0-based index and monitors are sorted top-to-bottom, left-to-right
|
||||
fix: Windows | the Windows + shift + left/right arrow key shortcuts should be usable now
|
||||
|
||||
chg: bundling lightmap tiles into texture atlases for improved rendering performance
|
||||
|
||||
chg: faster map loads by limiting the rendering back-end's frame-rate
|
||||
|
@ -36,7 +42,7 @@ fix: the last byte of a maximum length bitstream string wasn't parsed ("q3msgboo
|
|||
fix: aborting demo playback would crash when the "nextdemo" cvar was set to play a demo
|
||||
|
||||
fix: no longer feeding cs commands that came from a previous gamestate to cgame
|
||||
example: "/map cpm22" -> "/cv map cpm25" -> elevator sound was broken
|
||||
example in CPMA: "/map cpm22" -> "/cv map cpm25" -> elevator sound was broken
|
||||
|
||||
fix: on Windows, could sometimes click outside the engine's window in raw mouse input mode
|
||||
|
||||
|
@ -50,7 +56,7 @@ fix: /video and /stopvideo fixes
|
|||
fix: broken raw video output when r_width wasn't a multiple of 4
|
||||
fix: /stopvideo no longer leaves sound output broken for a while after stopping
|
||||
|
||||
fix: /cv and /callvote auto-completion were disabled after cgame was shut down at least once
|
||||
fix: /cv and /callvote map auto-completion was disabled after cgame was shut down at least once
|
||||
|
||||
|
||||
12 Feb 18 - 1.50
|
||||
|
|
5
code/linux/linux_help.h
Normal file
5
code/linux/linux_help.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define help_r_monitor \
|
||||
"0-based monitor index\n" \
|
||||
"Use /" S_COLOR_CMD "monitorlist " S_COLOR_HELP "to print the list of detected monitors.\n" \
|
||||
"The monitors are ordered top-to-bottom and left-to-right.\n" \
|
||||
"This means " S_COLOR_VAL "0 " S_COLOR_HELP "specifies the top-left monitor."
|
|
@ -1,4 +1,5 @@
|
|||
#include "linux_local.h"
|
||||
#include "linux_help.h"
|
||||
#include "../renderer/tr_local.h"
|
||||
#include "../renderer/qgl.h"
|
||||
|
||||
|
@ -14,13 +15,13 @@ static cvar_t* r_monitor; // 1-based, 0 means use primary monitor
|
|||
|
||||
static const cvarTableItem_t glimp_cvars[] = {
|
||||
{ &r_fullscreen, "r_fullscreen", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "full-screen mode" },
|
||||
{ &r_monitor, "r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", NULL, "1-based monitor index, 0=primary" }
|
||||
{ &r_monitor, "r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", NULL, help_r_monitor }
|
||||
};
|
||||
|
||||
static void sdl_PrintMonitorList();
|
||||
static void sdl_MonitorList_f();
|
||||
|
||||
static const cmdTableItem_t glimp_cmds[] = {
|
||||
{ "monitorlist", &sdl_PrintMonitorList, NULL, "prints the list of monitors" }
|
||||
{ "monitorlist", &sdl_MonitorList_f, NULL, "refreshes and prints the monitor list" }
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,26 +29,32 @@ static qbool sdl_IsMonitorListValid()
|
|||
{
|
||||
const int count = glimp.monitorCount;
|
||||
const int curr = glimp.monitor;
|
||||
const int prim = glimp.primaryMonitor;
|
||||
|
||||
return
|
||||
count >= 1 &&
|
||||
curr >= 0 &&
|
||||
curr < count &&
|
||||
prim >= 0 &&
|
||||
prim < count &&
|
||||
glimp.monitorRects[prim].x == 0 &&
|
||||
glimp.monitorRects[prim].y == 0;
|
||||
count >= 1 && count <= MAX_MONITOR_COUNT &&
|
||||
curr >= 0 && curr < count;
|
||||
}
|
||||
|
||||
|
||||
static int sdl_CompareMonitorRects( const void* aPtr, const void* bPtr )
|
||||
{
|
||||
const SDL_Rect* const a = (const SDL_Rect*)aPtr;
|
||||
const SDL_Rect* const b = (const SDL_Rect*)bPtr;
|
||||
const int dy = a->y - b->y;
|
||||
if (dy != 0)
|
||||
return dy;
|
||||
|
||||
return a->x - b->x;
|
||||
}
|
||||
|
||||
|
||||
static void sdl_CreateMonitorList()
|
||||
{
|
||||
glimp.monitorCount = 0;
|
||||
|
||||
const int count = SDL_GetNumVideoDisplays();
|
||||
if (count <= 0) {
|
||||
glimp.monitorCount = 0;
|
||||
if (count <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
int gi = 0;
|
||||
for (int si = 0; si < count; ++si) {
|
||||
|
@ -58,17 +65,9 @@ static void sdl_CreateMonitorList()
|
|||
}
|
||||
glimp.monitorCount = gi;
|
||||
|
||||
glimp.primaryMonitor = -1;
|
||||
const int finalCount = glimp.monitorCount;
|
||||
for(int i = 0; i < finalCount; ++i) {
|
||||
const SDL_Rect rect = glimp.monitorRects[i];
|
||||
if (rect.x == 0 && rect.y == 0) {
|
||||
glimp.primaryMonitor = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sdl_IsMonitorListValid())
|
||||
if (sdl_IsMonitorListValid())
|
||||
qsort(glimp.monitorRects, (size_t)glimp.monitorCount, sizeof(glimp.monitorRects[0]), &sdl_CompareMonitorRects);
|
||||
else
|
||||
glimp.monitorCount = 0;
|
||||
}
|
||||
|
||||
|
@ -76,15 +75,15 @@ static void sdl_CreateMonitorList()
|
|||
// call this before creating the window
|
||||
static void sdl_UpdateMonitorIndexFromCvar()
|
||||
{
|
||||
if (glimp.monitorCount <= 0)
|
||||
if (glimp.monitorCount <= 0 || glimp.monitorCount >= MAX_MONITOR_COUNT)
|
||||
return;
|
||||
|
||||
const int monitor = Cvar_Get("r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH)->integer;
|
||||
if (monitor <= 0 || monitor > glimp.monitorCount) {
|
||||
glimp.monitor = glimp.primaryMonitor;
|
||||
if (monitor < 0 || monitor >= glimp.monitorCount) {
|
||||
glimp.monitor = 0;
|
||||
return;
|
||||
}
|
||||
glimp.monitor = Com_ClampInt(0, glimp.monitorCount - 1, monitor - 1);
|
||||
glimp.monitor = monitor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,25 +95,20 @@ void sdl_UpdateMonitorIndexFromWindow()
|
|||
|
||||
// update the glimp index
|
||||
const int current = SDL_GetWindowDisplayIndex(glimp.window);
|
||||
if (current < 0) {
|
||||
if (current < 0 || current >= glimp.monitorCount) {
|
||||
glimp.monitorCount = 0;
|
||||
return;
|
||||
}
|
||||
glimp.monitor = current;
|
||||
|
||||
// update the cvar index
|
||||
if( r_monitor->integer == 0 &&
|
||||
glimp.monitor == glimp.primaryMonitor)
|
||||
return;
|
||||
Cvar_Set("r_monitor", va("%d", glimp.monitor + 1));
|
||||
Cvar_Set("r_monitor", va("%d", glimp.monitor));
|
||||
}
|
||||
|
||||
|
||||
static void sdl_GetSafeDesktopRect( SDL_Rect* rect )
|
||||
{
|
||||
if (glimp.monitorCount <= 0 ||
|
||||
glimp.monitor < 0 ||
|
||||
glimp.monitor >= glimp.monitorCount) {
|
||||
if (!sdl_IsMonitorListValid()) {
|
||||
rect->x = 0;
|
||||
rect->y = 0;
|
||||
rect->w = 1280;
|
||||
|
@ -128,15 +122,27 @@ static void sdl_GetSafeDesktopRect( SDL_Rect* rect )
|
|||
static void sdl_PrintMonitorList()
|
||||
{
|
||||
const int count = glimp.monitorCount;
|
||||
Com_Printf("Monitor count: %d\n", count);
|
||||
if (count <= 0) {
|
||||
Com_Printf("No monitor detected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf("Monitors detected (left is " S_COLOR_CVAR "r_monitor ^7value):\n");
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const SDL_Rect rect = glimp.monitorRects[i];
|
||||
Com_Printf("Monitor #%d: %d,%d %dx%d\n", i + 1, rect.x, rect.y, rect.w, rect.h);
|
||||
Com_Printf(S_COLOR_VAL "%d ^7%dx%d at %d,%d\n", i, rect.w, rect.h, rect.x, rect.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sdl_MonitorList_f()
|
||||
{
|
||||
sdl_CreateMonitorList();
|
||||
sdl_UpdateMonitorIndexFromCvar();
|
||||
sdl_PrintMonitorList();
|
||||
}
|
||||
|
||||
|
||||
void Sys_GL_Init()
|
||||
{
|
||||
if (glimp.window != NULL)
|
||||
|
|
|
@ -10,8 +10,7 @@ struct glImp_t {
|
|||
|
||||
SDL_Rect monitorRects[MAX_MONITOR_COUNT];
|
||||
int monitorCount;
|
||||
int primaryMonitor; // primary monitor, 0-based
|
||||
int monitor; // current monitor, 0-based
|
||||
int monitor; // current monitor, 0-based
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -413,8 +413,10 @@ static qbool GLW_CreateWindow()
|
|||
const int x = monRect.left + dx;
|
||||
const int y = monRect.top + dy;
|
||||
|
||||
g_wv.duringCreateWindow = qtrue;
|
||||
g_wv.hWnd = CreateWindowEx( exstyle, CLIENT_WINDOW_TITLE, " " CLIENT_WINDOW_TITLE, style,
|
||||
x, y, w, h, NULL, NULL, g_wv.hInstance, NULL );
|
||||
g_wv.duringCreateWindow = qfalse;
|
||||
|
||||
if ( !g_wv.hWnd )
|
||||
ri.Error( ERR_FATAL, "GLW_CreateWindow() - Couldn't create window" );
|
||||
|
@ -550,6 +552,7 @@ void WIN_SetDesktopDisplaySettings()
|
|||
|
||||
static qbool GLW_SetMode()
|
||||
{
|
||||
WIN_InitMonitorList();
|
||||
WIN_UpdateMonitorIndexFromCvar();
|
||||
|
||||
const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
|
||||
|
|
|
@ -6,4 +6,8 @@ S_COLOR_VAL " 2 " S_COLOR_HELP "= Win32 input"
|
|||
|
||||
#define help_in_minimize \
|
||||
"hotkey to minimize/restore the window\n" \
|
||||
"Use " S_COLOR_CMD "minimizekeynames " S_COLOR_HELP "to print the list of usable key names."
|
||||
"Use /" S_COLOR_CMD "minimizekeynames " S_COLOR_HELP "to print the list of usable key names."
|
||||
|
||||
#define help_r_monitor \
|
||||
"1-based monitor index, 0=primary\n" \
|
||||
"Use /" S_COLOR_CMD "monitorlist " S_COLOR_HELP "to print the list of detected monitors."
|
||||
|
|
|
@ -38,6 +38,7 @@ qbool IN_ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); // returns tr
|
|||
void IN_Frame();
|
||||
|
||||
// misc. Windows-specific stuff
|
||||
void WIN_InitMonitorList();
|
||||
void WIN_UpdateMonitorIndexFromCvar();
|
||||
void WIN_UpdateMonitorIndexFromMainWindow();
|
||||
void WIN_UpdateResolution( int width, int height );
|
||||
|
@ -73,6 +74,8 @@ typedef struct {
|
|||
// using Sys_Milliseconds
|
||||
int sysMsgTime;
|
||||
|
||||
qbool duringCreateWindow; // qtrue during the call to CreateWindow
|
||||
|
||||
RECT monitorRects[MAX_MONITOR_COUNT];
|
||||
HMONITOR hMonitors[MAX_MONITOR_COUNT];
|
||||
int monitor; // 0-based index of the monitor currently used for display
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "../client/client.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "win_local.h"
|
||||
#include "win_help.h"
|
||||
#include "resource.h"
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
|
@ -653,8 +654,12 @@ static BOOL CALLBACK WIN_MonitorEnumCallback( HMONITOR hMonitor, HDC hdcMonitor,
|
|||
}
|
||||
|
||||
|
||||
static void WIN_InitMonitorList()
|
||||
void WIN_InitMonitorList()
|
||||
{
|
||||
g_wv.monitor = 0;
|
||||
g_wv.primaryMonitor = 0;
|
||||
g_wv.monitorCount = 0;
|
||||
|
||||
EnumDisplayMonitors( NULL, NULL, &WIN_MonitorEnumCallback, 0 );
|
||||
|
||||
const POINT zero = { 0, 0 };
|
||||
|
@ -675,7 +680,7 @@ void WIN_UpdateMonitorIndexFromCvar()
|
|||
// use Cvar_Get to enforce the latched change, if any
|
||||
const int monitor = Cvar_Get( "r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH )->integer;
|
||||
Cvar_SetRange( "r_monitor", CVART_INTEGER, "0", va("%d", g_wv.monitorCount) );
|
||||
Cvar_SetHelp( "r_monitor", "1-based monitor index, 0=primary" );
|
||||
Cvar_SetHelp( "r_monitor", help_r_monitor );
|
||||
if ( monitor <= 0 || monitor > g_wv.monitorCount ) {
|
||||
g_wv.monitor = g_wv.primaryMonitor;
|
||||
return;
|
||||
|
@ -707,6 +712,36 @@ void WIN_UpdateMonitorIndexFromMainWindow()
|
|||
}
|
||||
|
||||
|
||||
static void WIN_MonitorList_f()
|
||||
{
|
||||
WIN_InitMonitorList();
|
||||
WIN_UpdateMonitorIndexFromCvar();
|
||||
|
||||
if ( g_wv.monitorCount <= 0 ) {
|
||||
Com_Printf( "No monitor detected.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf( "Monitors detected (left is " S_COLOR_CVAR "r_monitor ^7value):\n" );
|
||||
for ( int i = 0; i < g_wv.monitorCount; i++ ) {
|
||||
const RECT r = g_wv.monitorRects[i];
|
||||
const int w = (int)( r.right - r.left );
|
||||
const int h = (int)( r.bottom - r.top );
|
||||
const char* const p = i == g_wv.primaryMonitor ? " (primary)" : "";
|
||||
Com_Printf( S_COLOR_VAL "%d ^7%dx%d at %d,%d%s\n",
|
||||
i + 1, w, h, (int)r.left, (int)r.top, p );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void WIN_RegisterMonitorCommands()
|
||||
{
|
||||
Cmd_AddCommand( "monitorlist", &WIN_MonitorList_f );
|
||||
Cmd_SetModule( "monitorlist", MODULE_CLIENT );
|
||||
Cmd_SetHelp( "monitorlist", "refreshes and prints the monitor list" );
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
@ -720,6 +755,7 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
|
|||
|
||||
WIN_InstallExceptionHandlers();
|
||||
|
||||
// done here so the early console can be shown on the primary monitor
|
||||
WIN_InitMonitorList();
|
||||
|
||||
// done before Com/Sys_Init since we need this for error output
|
||||
|
@ -732,6 +768,7 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
|
|||
Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
|
||||
Com_Init( sys_cmdline );
|
||||
WIN_RegisterExceptionCommands();
|
||||
WIN_RegisterMonitorCommands();
|
||||
|
||||
NET_Init();
|
||||
|
||||
|
|
|
@ -168,6 +168,8 @@ LRESULT CALLBACK MainWndProc (
|
|||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
static qbool draggingWindow = qfalse;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
|
@ -197,12 +199,16 @@ LRESULT CALLBACK MainWndProc (
|
|||
WIN_S_Mute( !g_wv.activeApp );
|
||||
break;
|
||||
|
||||
case WM_MOVING:
|
||||
draggingWindow = qtrue;
|
||||
break;
|
||||
|
||||
case WM_MOVE:
|
||||
{
|
||||
if (!r_fullscreen->integer )
|
||||
{
|
||||
WIN_UpdateMonitorIndexFromMainWindow();
|
||||
WIN_UpdateMonitorIndexFromMainWindow();
|
||||
|
||||
if ( !r_fullscreen->integer )
|
||||
{
|
||||
RECT r;
|
||||
r.left = 0;
|
||||
r.top = 0;
|
||||
|
@ -218,12 +224,33 @@ LRESULT CALLBACK MainWndProc (
|
|||
vid_xpos->modified = qfalse;
|
||||
vid_ypos->modified = qfalse;
|
||||
}
|
||||
|
||||
draggingWindow = qfalse;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
if ( wParam != SIZE_MINIMIZED )
|
||||
WIN_UpdateResolution( (int)LOWORD(lParam), (int)HIWORD(lParam) );
|
||||
if ( wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED )
|
||||
{
|
||||
WIN_UpdateMonitorIndexFromMainWindow();
|
||||
|
||||
// note that WM_SIZE can be called with no actual size change
|
||||
const int w = (int)LOWORD( lParam );
|
||||
const int h = (int)HIWORD( lParam );
|
||||
if ( g_wv.duringCreateWindow )
|
||||
WIN_UpdateResolution( w, h );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
const int prevMon = g_wv.monitor;
|
||||
WIN_UpdateMonitorIndexFromMainWindow();
|
||||
const int currMon = g_wv.monitor;
|
||||
|
||||
if ( !g_wv.duringCreateWindow && !draggingWindow && currMon != prevMon )
|
||||
Cbuf_AddText( "vid_restart\n" );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
|
|
Loading…
Reference in a new issue