reactos/base/applications/screensavers/3dtext/3dtext.c
Joachim Henze e04c22dc8a [0.4.13][USER32][NTUSER][3DTEXT] Squashed backport
[USER32] GetQueueStatus() should not return 0 when passing QS_ALLINPUT flag that includes QS_RAWINPUT (#4115)

GTK applications call GetQueueStatus(QS_ALLINPUT), where QS_ALLINPUT
specifies the QS_RAWINPUT flag as well, when these are compiled for
Windows XP+, and they expect the call to succeed on this platform.

On one side, ReactOS does not currently support this flag at all, but
since it claims to be XP/2003-compatible, applications may implicitly
expect the flag to be supported by GetQueueStatus() and the function
*NOT* failing when this flag is set.
(Later GTK apps don't care and just call GetQueueStatus(QS_ALLINPUT)
that includes QS_RAWINPUT, and therefore would fail as well on e.g.
Windows 2000...)

Otherwise, an observable effect is that some versions of libgdk-win32-2.0.0.dll
enter into an infinite loop when calling GetQueueStatus(QS_ALLINPUT),
since this call always failed on ReactOS.

On the other side, however, we should honour our winetests that handle
the presence of the QS_RAWINPUT flag and behave differently accordingly.
But since we do not support QS_RAWINPUT yet, we should keep their old
behaviour where QS_RAWINPUT is unused.

Thus, in order to accomodate both sides, we don't fail the GetQueueStatus()
call, but just set the ERROR_INVALID_FLAGS last error and continue it.

This fixes:
'All user32:TrackMouseEvent tests'
CORE-15686: Gimp 2.8.22 from rapps hangs after startup with 90%-100% CPU usage
and many dupes of that ticket like:
CORE-17551: Ardour hangs at the first start (GTK2 issue)
CORE-15151: newer "Inkscape 0.92.3" is unusable due to WIN32SS message queue lockup
CORE-14086: RawTherapee 5.0-r1-gtk2 fails to start (using 100% CPU)
CORE-11850: Geany 1.28 hangs with endless MsqSendMessage timed out
CORE-8475: Wireshark hangs after launch

It will also slightly appease, but not entirely fix:
CORE-8217: 3D Text ScreenSaver freezes system

Fix picked from 0.4.15-dev-3407-g 9c4397afdf
---------------------
[NTUSER] Do not remove message from the Msg Queue if it is not for us. (#4129)

CORE-8217 This part of the fix keeps the buttons working (Cancel/Ok/top-Right-X) even under high CPU-load
Patch from 'I_Kill_Bugs' contributor.

Fix picked from 0.4.15-dev-3499-g 7d1b50394b
---------------------
[3DTEXT] Fix 3dtext.scr using near 100% CPU (#4125) CORE-17866, CORE-8217

Fix picked from 0.4.15-dev-3443-g 5c9fdcb1de
2022-02-08 13:00:42 +01:00

435 lines
13 KiB
C

/*
* Copyright 2000 Jeff Molofee http://nehe.gamedev.net/ (Original code)
* Copyright 2006 Eric Kohl
* Copyright 2007 Marc Piulachs (marc.piulachs@codexchange.net) - minor modifications , converted to screensaver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "3dtext.h"
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
#include <scrnsave.h>
#include <math.h>
#include <GL/glu.h>
#include "resource.h"
static HGLRC hRC; // Permanent Rendering Context
static HDC hDC; // Private GDI Device Context
GLuint base; // Base Display List For The Font Set
GLfloat rot; // Used To Rotate The Text
GLfloat extentX = 0.0f;
GLfloat extentY = 0.0f;
#define APPNAME _T("3DText")
HINSTANCE hInstance;
BOOL fullscreen = FALSE;
UINT uTimerID; // SetTimer Actual ID
#define APP_TIMER 1 // Graphics Update Timer ID
#define APP_TIMER_INTERVAL (USER_TIMER_MINIMUM * 5) // Graphics Update Interval
// Build Our Bitmap Font
GLvoid BuildFont(GLvoid)
{
// Address Buffer For Font Storage
GLYPHMETRICSFLOAT gmf[256];
// Windows Font Handle
HFONT font;
size_t i;
TCHAR c;
GLfloat cellOriginX = 0.0f;
GLfloat stringOriginX;
GLfloat stringExtentX = 0.0f;
GLfloat stringExtentY = 0.0f;
// Storage For 256 Characters
base = glGenLists(256);
font = CreateFont(-12,
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
FW_BOLD, // Font Weight
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
DEFAULT_CHARSET, // Character Set Identifier
OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
_T("Tahoma")); // Font Name
// Selects The Font We Created
SelectObject(hDC, font);
wglUseFontOutlines(hDC, // Select The Current DC
0, // Starting Character
255, // Number Of Display Lists To Build
base, // Starting Display Lists
0.0f, // Deviation From The True Outlines
0.2f, // Font Thickness In The Z Direction
WGL_FONT_POLYGONS, // Use Polygons, Not Lines
gmf); // Address Of Buffer To Receive Data
// Calculate the string extent
for (i = 0; i < _tcslen(m_Text); i++)
{
c = m_Text[i];
stringOriginX = cellOriginX + gmf[c].gmfptGlyphOrigin.x;
stringExtentX = stringOriginX + gmf[c].gmfBlackBoxX;
if (gmf[c].gmfBlackBoxY > stringExtentY)
stringExtentY = gmf[c].gmfBlackBoxY;
cellOriginX = cellOriginX + gmf[c].gmfCellIncX;
}
extentX = stringExtentX;
extentY = stringExtentY;
}
// Delete The Font
GLvoid KillFont(GLvoid)
{
// Delete all 256 characters
glDeleteLists(base, 256);
}
// Custom GL "Print" Routine
GLvoid glPrint(LPTSTR text)
{
// If there's no text, do nothing
if (text == NULL)
return;
// Pushes The Display List Bits
glPushAttrib(GL_LIST_BIT);
// Sets The Base Character to 32
glListBase(base);
// Draws The Display List Text
glCallLists(_tcslen(text),
#ifdef UNICODE
GL_UNSIGNED_SHORT,
#else
GL_UNSIGNED_BYTE,
#endif
text);
// Pops The Display List Bits
glPopAttrib();
}
// Will Be Called Right After The GL Window Is Created
GLvoid InitGL(GLsizei Width, GLsizei Height)
{
// Clear The Background Color To Black
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Enables Clearing Of The Depth Buffer
glClearDepth(1.0);
// The Type Of Depth Test To Do
glDepthFunc(GL_LESS);
// Enables Depth Testing
glEnable(GL_DEPTH_TEST);
// Enables Smooth Color Shading
glShadeModel(GL_SMOOTH);
// Select The Projection Matrix
glMatrixMode(GL_PROJECTION);
// Reset The Projection Matrix
glLoadIdentity();
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
// Select The Modelview Matrix
glMatrixMode(GL_MODELVIEW);
// Build The Font
BuildFont();
// Enable Default Light (Quick And Dirty)
glEnable(GL_LIGHT0);
// Enable Lighting
glEnable(GL_LIGHTING);
// Enable Coloring Of Material
glEnable(GL_COLOR_MATERIAL);
}
// Handles Window Resizing
GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
{
// Is Window Too Small (Divide By Zero Error)
if (Height == 0)
{
// If So Make It One Pixel Tall
Height = 1;
}
// Reset The Current Viewport And Perspective Transformation
glViewport(0, 0, Width, Height);
// Select The Projection Matrix
glMatrixMode(GL_PROJECTION);
// Reset The Projection Matrix
glLoadIdentity();
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
// Select The Modelview Matrix
glMatrixMode(GL_MODELVIEW);
}
// Handles Rendering
GLvoid DrawGLScene(GLvoid)
{
// Save ticks count of previous frame here
static DWORD dwTicks = 0;
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The View
glLoadIdentity();
// Move One Unit Into The Screen
glTranslatef(0.0f, 0.0f, -10.0f);
// Rotate On The X Axis
glRotatef(rot, 1.0f, 0.0f, 0.0f);
// Rotate On The Y Axis
glRotatef(rot * 1.2f, 0.0f, 1.0f, 0.0f);
// Rotate On The Z Axis
glRotatef(rot * 1.4f, 0.0f, 0.0f, 1.0f);
// Move to the Left and Down before drawing
glTranslatef(-(extentX / 2.0f),
-(extentY / 2.0f),
0.0f);
// Pulsing Colors Based On The Rotation
glColor3f((1.0f * (GLfloat)(cos(rot / 20.0f))),
(1.0f * (GLfloat)(sin(rot / 25.0f))),
(1.0f - 0.5f * (GLfloat)(cos(rot / 17.0f))));
// Print GL Text To The Screen
glPrint(m_Text);
// Make The Text Blue
glColor3f(0.0f, 0.0f, 1.0f);
// Increase The Rotation Variable
if(dwTicks)
rot += (GetTickCount() - dwTicks) / 20.0f;
dwTicks = GetTickCount();
}
LRESULT CALLBACK
ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
RECT Screen; // Used Later On To Get The Size Of The Window
GLuint PixelFormat; // Pixel Format Storage
static PIXELFORMATDESCRIPTOR pfd= // Pixel Format Descriptor
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number (?)
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
16, // Select A 16Bit Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored (?)
0, // No Alpha Buffer
0, // Shift Bit Ignored (?)
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored (?)
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer (?)
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved (?)
0, 0, 0 // Layer Masks Ignored (?)
};
switch (message)
{
case WM_CREATE:
LoadSettings();
// Gets A Device Context For The Window
hDC = GetDC(hWnd);
// Finds The Closest Match To The Pixel Format We Set Above
PixelFormat = ChoosePixelFormat(hDC, &pfd);
// No Matching Pixel Format?
if (!PixelFormat)
{
MessageBox(0, _TEXT("Can't Find A Suitable PixelFormat."), _TEXT("Error"),MB_OK | MB_ICONERROR);
// This Sends A 'Message' Telling The Program To Quit
PostQuitMessage(0);
break;
}
// Can We Set The Pixel Mode?
if (!SetPixelFormat(hDC, PixelFormat, &pfd))
{
MessageBox(0, _TEXT("Can't Set The PixelFormat."), _TEXT("Error"), MB_OK | MB_ICONERROR);
// This Sends A 'Message' Telling The Program To Quit
PostQuitMessage(0);
break;
}
// Grab A Rendering Context
hRC = wglCreateContext(hDC);
// Did We Get One?
if (!hRC)
{
MessageBox(0, _TEXT("Can't Create A GL Rendering Context."), _TEXT("Error"), MB_OK | MB_ICONERROR);
// This Sends A 'Message' Telling The Program To Quit
PostQuitMessage(0);
break;
}
// Can We Make The RC Active?
if (!wglMakeCurrent(hDC, hRC))
{
MessageBox(0, _TEXT("Can't Activate GLRC."), _TEXT("Error"), MB_OK | MB_ICONERROR);
// This Sends A 'Message' Telling The Program To Quit
PostQuitMessage(0);
break;
}
// Grab Screen Info For The Current Window
GetClientRect(hWnd, &Screen);
// Initialize The GL Screen Using Screen Info
InitGL(Screen.right, Screen.bottom);
// Create Graphics update timer
uTimerID = SetTimer(hWnd, APP_TIMER, APP_TIMER_INTERVAL, NULL);
break;
case WM_DESTROY:
// Disable Fullscreen Mode
ChangeDisplaySettings(NULL, 0);
// Delete the Update Timer
KillTimer(hWnd, uTimerID);
// Deletes The Font Display List
KillFont();
// Make The DC Current
wglMakeCurrent(hDC, NULL);
// Kill The RC
wglDeleteContext(hRC);
// Free The DC
ReleaseDC(hWnd, hDC);
break;
case WM_PAINT:
DrawGLScene();
SwapBuffers(hDC);
// Mark this window as updated, so the OS won't ask us to update it again.
ValidateRect(hWnd, NULL);
break;
case WM_SIZE: // Resizing The Screen
// Resize To The New Window Size
ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
break;
case WM_TIMER:
// Used to update graphic based on timer udpate interval
InvalidateRect(hWnd, NULL, TRUE);
break;
default:
// Pass Windows Messages to the default screensaver window procedure
return DefScreenSaverProc(hWnd, message, wParam, lParam);
}
return 0;
}
//
// Dialogbox procedure for Configuration window
//
BOOL CALLBACK ScreenSaverConfigureDialog(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
LoadSettings();
SetDlgItemText(hDlg, IDC_MESSAGE_TEXT, m_Text);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
GetDlgItemText(hDlg, IDC_MESSAGE_TEXT, m_Text, MAX_PATH);
SaveSettings();
/* Fall through */
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
return FALSE;
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
default:
return FALSE;
}
return TRUE;
}
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
return TRUE;
}