mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-21 04:53:37 +01:00
298 lines
8.7 KiB
C++
298 lines
8.7 KiB
C++
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
|
//
|
|
// This file is part of the VNC system.
|
|
//
|
|
// The VNC system 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// If the source code for the VNC system is not available from the place
|
|
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
|
|
// the authors on vnc@uk.research.att.com for information on obtaining it.
|
|
|
|
|
|
// Flasher.cpp: implementation of the Flasher class.
|
|
|
|
#include "stdhdrs.h"
|
|
#include "vncviewer.h"
|
|
#include "Flasher.h"
|
|
#include "Exception.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#define FLASHER_CLASS_NAME "VNCviewer Flasher"
|
|
#define FLASHFONTHEIGHT 80
|
|
|
|
extern char sz_G1[64];
|
|
extern char sz_G2[64];
|
|
extern char sz_G3[64];
|
|
|
|
Flasher::Flasher(int port)
|
|
{
|
|
// Create a dummy window. We don't use it for anything except
|
|
// receiving socket events, so a seperate listening thread would
|
|
// probably be easier!
|
|
|
|
WNDCLASSEX wndclass;
|
|
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW;
|
|
wndclass.lpfnWndProc = Flasher::WndProc;
|
|
wndclass.cbClsExtra = 0;
|
|
wndclass.cbWndExtra = 0;
|
|
wndclass.hInstance = pApp->m_instance;
|
|
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
|
|
wndclass.lpszMenuName = (const char *) NULL;
|
|
wndclass.lpszClassName = FLASHER_CLASS_NAME;
|
|
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
RegisterClassEx(&wndclass);
|
|
|
|
m_hwnd = CreateWindow(FLASHER_CLASS_NAME,
|
|
FLASHER_CLASS_NAME,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
200, 200,
|
|
NULL,
|
|
NULL,
|
|
pApp->m_instance,
|
|
NULL);
|
|
|
|
// record which client created this window
|
|
SetWindowLong(m_hwnd, GWL_USERDATA, (LONG) this);
|
|
|
|
// Select a font for displaying user name
|
|
LOGFONT lf;
|
|
memset(&lf, 0, sizeof(lf));
|
|
lf.lfHeight = FLASHFONTHEIGHT;
|
|
lf.lfWeight = FW_BOLD;
|
|
lf.lfItalic = 1;
|
|
lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
|
|
lf.lfFaceName[0] = '\0';
|
|
m_hfont = CreateFontIndirect(&lf);
|
|
if (m_hfont == NULL) {
|
|
vnclog.Print(1, _T("FAILED TO SELECT FLASHER FONT!\n"));
|
|
}
|
|
|
|
// Create a listening socket
|
|
struct sockaddr_in addr;
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (!m_sock) throw WarningException(sz_G1);
|
|
|
|
try {
|
|
int one = 1, res = 0;
|
|
|
|
// If we use the SO_REUSEADDR option then you can run multiple daemons
|
|
// because the bind doesn't return an error. Only one gets the accept,
|
|
// but when that process dies it hands back to another. This may or may
|
|
// not be desirable. We don't use it.
|
|
|
|
//int res = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &one, sizeof(one));
|
|
//if (res == SOCKET_ERROR)
|
|
// throw WarningException("Error setting Flasher socket options");
|
|
|
|
res = bind(m_sock, (struct sockaddr *)&addr, sizeof(addr));
|
|
if (res == SOCKET_ERROR)
|
|
throw WarningException(sz_G2);
|
|
|
|
res = listen(m_sock, 5);
|
|
if (res == SOCKET_ERROR)
|
|
throw WarningException(sz_G3);
|
|
} catch (...) {
|
|
closesocket(m_sock);
|
|
m_sock = 0;
|
|
throw;
|
|
}
|
|
|
|
// Send a message to specified window on an incoming connection
|
|
WSAAsyncSelect (m_sock, m_hwnd, WM_SOCKEVENT, FD_ACCEPT | FD_CLOSE);
|
|
}
|
|
|
|
// convert a lower-case ASCII char to a value 0-255
|
|
inline int scalechar(char c) {
|
|
return ( ((c - 'a')+4) & 0x1f ) * 255 / 0x1f;
|
|
}
|
|
|
|
// We use this on each screen saver window running
|
|
BOOL CALLBACK KillScreenSaverFunc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
char buffer[256];
|
|
|
|
// - ONLY try to close Screen-saver windows!!!
|
|
if ((GetClassName(hwnd, buffer, 256) != 0) &&
|
|
(strcmp(buffer, "WindowsScreenSaverClass") == 0))
|
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
// Process window messages
|
|
LRESULT CALLBACK Flasher::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
|
|
// This is a static method, so we don't know which instantiation we're
|
|
// dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion
|
|
// from a newsgroup to get the pseudo-this.
|
|
Flasher *_this = (Flasher *) GetWindowLong(hwnd, GWL_USERDATA);
|
|
|
|
switch (iMsg) {
|
|
|
|
case WM_CREATE:
|
|
return 0;
|
|
|
|
case WM_SOCKEVENT:
|
|
{
|
|
assert(HIWORD(lParam) == 0);
|
|
|
|
// A new socket created by accept might send messages to
|
|
// this procedure. We can ignore them.
|
|
if(wParam != _this->m_sock) {
|
|
return 0;
|
|
}
|
|
|
|
switch(lParam) {
|
|
case FD_ACCEPT:
|
|
{
|
|
SOCKET hNewSock;
|
|
char username[256];
|
|
hNewSock = accept(_this->m_sock, NULL, NULL);
|
|
// make it blocking
|
|
WSAAsyncSelect(hNewSock, hwnd, 0, 0);
|
|
u_long blk = 0;
|
|
int res = ioctlsocket(hNewSock, FIONBIO, &blk);
|
|
assert(res == 0);
|
|
|
|
CloseScreenSaver();
|
|
|
|
// Se if the server's sending a user name
|
|
int namelen = recv(hNewSock, username, 250, 0);
|
|
if (namelen >= 0)
|
|
username[namelen] = 0;
|
|
vnclog.Print(2, _T("Flash for '%s'\n"), username);
|
|
|
|
closesocket(hNewSock);
|
|
|
|
|
|
// flash
|
|
// Get a DC for the root window
|
|
HDC hrootdc = ::GetDC(NULL);
|
|
|
|
HBRUSH holdbrush = (HBRUSH) SelectObject(hrootdc,
|
|
(HBRUSH) GetStockObject(BLACK_BRUSH));
|
|
|
|
// Find the size.
|
|
RECT rect;
|
|
GetClipBox(hrootdc, &rect);
|
|
int barwidth = (rect.right - rect.left) / 10;
|
|
int barheight = max(
|
|
(rect.bottom - rect.top) / 10,
|
|
FLASHFONTHEIGHT);
|
|
HFONT oldfont = (HFONT) SelectObject(hrootdc, _this->m_hfont);
|
|
|
|
// Flash the screen
|
|
::Beep(440,50);
|
|
|
|
Rectangle(hrootdc, rect.left, rect.top,
|
|
rect.right, barheight);
|
|
Rectangle(hrootdc, rect.left, rect.bottom-barheight,
|
|
rect.right, rect.bottom);
|
|
Rectangle(hrootdc, rect.left, rect.top+barheight,
|
|
barwidth, rect.bottom-barheight);
|
|
Rectangle(hrootdc, rect.right-barwidth, rect.top+barheight,
|
|
rect.right, rect.bottom-barheight);
|
|
|
|
RECT topbar;
|
|
SetRect(&topbar, rect.left, rect.top,
|
|
rect.right, barheight);
|
|
int i = 0;
|
|
if (namelen > 0) {
|
|
int oldmode = SetBkMode(hrootdc, TRANSPARENT);
|
|
COLORREF oldcolor = SetTextColor(hrootdc,
|
|
RGB(scalechar(username[0])/(i+1), scalechar(username[1])/(i+1), scalechar(username[2])/(i+1)));
|
|
DrawText(hrootdc, username, -1, &topbar, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
SetTextColor(hrootdc, oldcolor);
|
|
SetBkMode(hrootdc, oldmode);
|
|
}
|
|
GdiFlush();
|
|
SelectObject(hrootdc, holdbrush);
|
|
::Sleep(1000);
|
|
|
|
SelectObject(hrootdc, oldfont);
|
|
InvalidateRect(0, &rect, TRUE);
|
|
|
|
::ReleaseDC(NULL, hrootdc);
|
|
break;
|
|
}
|
|
case FD_CLOSE:
|
|
vnclog.Print(2, _T("Flasher connection closed\n"));
|
|
DestroyWindow(hwnd);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProc(hwnd, iMsg, wParam, lParam);
|
|
}
|
|
|
|
void Flasher::CloseScreenSaver() {
|
|
// Which OS are we on?
|
|
OSVERSIONINFO ovi;
|
|
ovi.dwOSVersionInfoSize = sizeof(ovi);
|
|
if (!GetVersionEx(&ovi)) return;
|
|
|
|
switch (ovi.dwPlatformId) {
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
{
|
|
// Windows 95
|
|
HWND hsswnd = FindWindow ("WindowsScreenSaverClass", NULL);
|
|
if (hsswnd != NULL)
|
|
PostMessage(hsswnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
case VER_PLATFORM_WIN32_NT:
|
|
{
|
|
// Windows NT
|
|
HDESK hdesk = OpenDesktop(
|
|
TEXT("Screen-saver"),
|
|
0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
|
|
if (hdesk) {
|
|
if (EnumDesktopWindows(hdesk, (WNDENUMPROC) KillScreenSaverFunc, 0)) {
|
|
CloseDesktop(hdesk);
|
|
}
|
|
Sleep(1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Flasher::~Flasher()
|
|
{
|
|
shutdown(m_sock, SD_BOTH);
|
|
closesocket(m_sock);
|
|
if (m_hfont != NULL) DeleteObject(m_hfont);
|
|
}
|
|
|