~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to ica/win32/src/vncDesktop.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080617134654-cl0gi4u524cv1ici
Tags: 1:1.0.9~rc3-1
* Package new upstream version
  - upstream ported the code to qt4.4 (Closes: #481974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//  Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
 
2
//  Copyright (C) 2001-2004 TightVNC Team. All Rights Reserved.
 
3
//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
 
4
//
 
5
//  This file is part of the VNC system.
 
6
//
 
7
//  The VNC system is free software; you can redistribute it and/or modify
 
8
//  it under the terms of the GNU General Public License as published by
 
9
//  the Free Software Foundation; either version 2 of the License, or
 
10
//  (at your option) any later version.
 
11
//
 
12
//  This program is distributed in the hope that it will be useful,
 
13
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
//  GNU General Public License for more details.
 
16
//
 
17
//  You should have received a copy of the GNU General Public License
 
18
//  along with this program; if not, write to the Free Software
 
19
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 
20
//  USA.
 
21
//
 
22
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
 
23
//
 
24
// If the source code for the VNC system is not available from the place 
 
25
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
 
26
// the authors on vnc@uk.research.att.com for information on obtaining it.
 
27
 
 
28
// vncDesktop implementation
 
29
 
 
30
// System headers
 
31
#include "stdhdrs.h"
 
32
#include <omnithread.h>
 
33
 
 
34
// Custom headers
 
35
#include "WinVNC.h"
 
36
#include "VNCHooks/VNCHooks.h"
 
37
#include "vncServer.h"
 
38
#include "vncRegion.h"
 
39
#include "rectlist.h"
 
40
#include "vncDesktop.h"
 
41
#include "vncService.h"
 
42
#include "WallpaperUtils.h"
 
43
//#include "TsSessions.h"
 
44
 
 
45
#if (_MSC_VER>= 1300)
 
46
#include <fstream>
 
47
#else
 
48
#include <fstream>
 
49
#endif
 
50
 
 
51
// Constants
 
52
const UINT RFB_SCREEN_UPDATE = RegisterWindowMessage("WinVNC.Update.DrawRect");
 
53
const UINT RFB_COPYRECT_UPDATE = RegisterWindowMessage("WinVNC.Update.CopyRect");
 
54
const UINT RFB_MOUSE_UPDATE = RegisterWindowMessage("WinVNC.Update.Mouse");
 
55
// Messages for blocking remote input events
 
56
const UINT RFB_LOCAL_KEYBOARD = RegisterWindowMessage("WinVNC.Local.Keyboard");
 
57
const UINT RFB_LOCAL_MOUSE = RegisterWindowMessage("WinVNC.Local.Mouse");
 
58
 
 
59
const char szDesktopSink[] = "WinVNC desktop sink";
 
60
 
 
61
// Atoms
 
62
const char *VNC_WINDOWPOS_ATOMNAME = "VNCHooks.CopyRect.WindowPos";
 
63
ATOM VNC_WINDOWPOS_ATOM = (ATOM) NULL;
 
64
 
 
65
// Static members to use with new polling algorithm
 
66
const int vncDesktop::m_pollingOrder[32] = {
 
67
         0, 16,  8, 24,  4, 20, 12, 28,
 
68
        10, 26, 18,  2, 22,  6, 30, 14,
 
69
         1, 17,  9, 25,  7, 23, 15, 31,
 
70
        19,  3, 27, 11, 29, 13,  5, 21
 
71
};
 
72
int vncDesktop::m_pollingStep = 0;
 
73
 
 
74
 
 
75
BOOL IsWinNT()
 
76
{
 
77
        return vncService::IsWinNT();
 
78
}
 
79
 
 
80
BOOL IsWinVerOrHigher(ULONG mj, ULONG mn)
 
81
{
 
82
        return vncService::VersionMajor() > mj ||
 
83
                vncService::VersionMajor() == mj && vncService::VersionMinor() >= mn;
 
84
}
 
85
 
 
86
BOOL IsNtVer(ULONG mj, ULONG mn)
 
87
{
 
88
        if (!vncService::IsWinNT())     
 
89
                return FALSE;
 
90
        return vncService::VersionMajor() == mj && vncService::VersionMinor() == mn;
 
91
}
 
92
 
 
93
BOOL vncDesktop::IsMultiMonDesktop()
 
94
{
 
95
        if (!IsWinVerOrHigher(4, 10))
 
96
                return FALSE;
 
97
        return GetSystemMetrics(SM_CMONITORS) > 1;
 
98
}
 
99
 
 
100
// The desktop handler thread
 
101
// This handles the messages posted by RFBLib to the vncDesktop window
 
102
 
 
103
class vncDesktopThread : public omni_thread
 
104
{
 
105
public:
 
106
        vncDesktopThread() { m_returnsig = NULL; }
 
107
protected:
 
108
        ~vncDesktopThread() { if (m_returnsig != NULL) delete m_returnsig; }
 
109
public:
 
110
        virtual BOOL Init(vncDesktop *desktop, vncServer *server);
 
111
        virtual void *run_undetached(void *arg);
 
112
        virtual void ReturnVal(BOOL result);
 
113
 
 
114
protected:
 
115
        vncServer *m_server;
 
116
        vncDesktop *m_desktop;
 
117
 
 
118
        omni_mutex m_returnLock;
 
119
        omni_condition *m_returnsig;
 
120
        BOOL m_return;
 
121
        BOOL m_returnset;
 
122
};
 
123
 
 
124
BOOL
 
125
vncDesktopThread::Init(vncDesktop *desktop, vncServer *server)
 
126
{
 
127
        // Save the server pointer
 
128
        m_server = server;
 
129
        m_desktop = desktop;
 
130
 
 
131
        m_returnset = FALSE;
 
132
        m_returnsig = new omni_condition(&m_returnLock);
 
133
 
 
134
        // Start the thread
 
135
        start_undetached();
 
136
 
 
137
        // Wait for the thread to let us know if it failed to init
 
138
        {       omni_mutex_lock l(m_returnLock);
 
139
 
 
140
                while (!m_returnset)
 
141
                {
 
142
                        m_returnsig->wait();
 
143
                }
 
144
        }
 
145
 
 
146
        return m_return;
 
147
}
 
148
 
 
149
void
 
150
vncDesktopThread::ReturnVal(BOOL result)
 
151
{
 
152
        omni_mutex_lock l(m_returnLock);
 
153
 
 
154
        m_returnset = TRUE;
 
155
        m_return = result;
 
156
        m_returnsig->signal();
 
157
}
 
158
 
 
159
void *vncDesktopThread::run_undetached(void *arg)
 
160
{
 
161
        // Save the thread's "home" desktop, under NT (no effect under 9x)
 
162
        HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());
 
163
 
 
164
#if 0
 
165
        // Try to make session zero the console session
 
166
        if (!inConsoleSession())
 
167
                setConsoleSession();
 
168
#endif
 
169
 
 
170
        // Attempt to initialise and return success or failure
 
171
        if (!m_desktop->Startup())
 
172
        {
 
173
// vncDesktop::Startup might mave changed video mode in SetupDisplayForConnection.
 
174
// it has to be reverted then.
 
175
// TODO: review strong guarantee conditions for vncDesktop::Startup
 
176
                m_desktop->ResetDisplayToNormal();
 
177
                vncService::SelectHDESK(home_desktop);
 
178
                ReturnVal(FALSE);
 
179
                return NULL;
 
180
        }
 
181
 
 
182
        RECT rect = m_desktop->GetSourceRect();
 
183
        IntersectRect(&rect, &rect, &m_desktop->m_bmrect);
 
184
        m_server->SetSharedRect(rect);
 
185
 
 
186
        // Succeeded to initialise ok
 
187
        ReturnVal(TRUE);
 
188
 
 
189
        // START PROCESSING DESKTOP MESSAGES
 
190
 
 
191
        // We set a flag inside the desktop handler here, to indicate it's now safe
 
192
        // to handle clipboard messages
 
193
        m_desktop->SetClipboardActive(TRUE);
 
194
 
 
195
        SYSTEMTIME systime;
 
196
        FILETIME ftime;
 
197
        ULARGE_INTEGER now, droptime;
 
198
        droptime.QuadPart = 0;
 
199
 
 
200
        MSG msg;
 
201
        while (TRUE)
 
202
        {
 
203
                if (!PeekMessage(&msg, m_desktop->Window(), (UINT) NULL, (UINT) NULL, PM_REMOVE))
 
204
                {
 
205
                        // Whenever the message queue becomes empty, we check to see whether
 
206
                        // there are updates to be passed to clients (first we make sure
 
207
                        // that scheduled wallpaper removal is complete).
 
208
                        if (!m_server->WallpaperWait()) {
 
209
                                if (!m_desktop->CheckUpdates())
 
210
                                        break;
 
211
                        }
 
212
 
 
213
                        // Now wait for more messages to be queued
 
214
                        if (!WaitMessage())
 
215
                        {
 
216
                                vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n"));
 
217
                                break;
 
218
                        }
 
219
                }
 
220
                else if (msg.message == RFB_SCREEN_UPDATE)
 
221
                {
 
222
// TODO: suppress this message from hook when driver is active
 
223
 
 
224
                        // An area of the screen has changed (ignore if we have a driver)
 
225
                        if (m_desktop->m_videodriver == NULL)
 
226
                        {
 
227
                                RECT rect;
 
228
                                rect.left =     (SHORT)LOWORD(msg.wParam);
 
229
                                rect.top = (SHORT)HIWORD(msg.wParam);
 
230
                                rect.right = (SHORT)LOWORD(msg.lParam);
 
231
                                rect.bottom = (SHORT)HIWORD(msg.lParam);
 
232
                                m_desktop->m_changed_rgn.AddRect(rect);
 
233
                        }
 
234
                }
 
235
                else if (msg.message == RFB_MOUSE_UPDATE)
 
236
                {
 
237
                        // Save the cursor ID
 
238
                        m_desktop->SetCursor((HCURSOR) msg.wParam);
 
239
                }
 
240
                else if (msg.message == RFB_LOCAL_KEYBOARD)
 
241
                {
 
242
                        // Block remote input events if necessary
 
243
                        if (vncService::IsWin95()) {
 
244
                                m_server->SetKeyboardCounter(-1);
 
245
                                if (m_server->KeyboardCounter() < 0) {
 
246
                                        GetSystemTime(&systime);
 
247
                                        SystemTimeToFileTime(&systime, &ftime);
 
248
                                        droptime.LowPart = ftime.dwLowDateTime; 
 
249
                                        droptime.HighPart = ftime.dwHighDateTime;
 
250
                                        droptime.QuadPart /= 10000000;  // convert into seconds
 
251
                                        m_server->BlockRemoteInput(true);
 
252
                                }
 
253
                        } else {
 
254
                                GetSystemTime(&systime);
 
255
                                SystemTimeToFileTime(&systime, &ftime);
 
256
                                droptime.LowPart = ftime.dwLowDateTime; 
 
257
                                droptime.HighPart = ftime.dwHighDateTime;
 
258
                                droptime.QuadPart /= 10000000;  // convert into seconds
 
259
                                m_server->BlockRemoteInput(true);
 
260
                        }
 
261
                }
 
262
                else if (msg.message == RFB_LOCAL_MOUSE)
 
263
                {
 
264
                        // Block remote input events if necessary
 
265
                        if (vncService::IsWin95()) {
 
266
                                if (msg.wParam == WM_MOUSEMOVE) {
 
267
                                        m_server->SetMouseCounter(-1, msg.pt, true);
 
268
                                } else {
 
269
                                        m_server->SetMouseCounter(-1, msg.pt, false);
 
270
                                }
 
271
                                if (m_server->MouseCounter() < 0 && droptime.QuadPart == 0) {
 
272
                                        GetSystemTime(&systime);
 
273
                                        SystemTimeToFileTime(&systime, &ftime);
 
274
                                        droptime.LowPart = ftime.dwLowDateTime; 
 
275
                                        droptime.HighPart = ftime.dwHighDateTime;
 
276
                                        droptime.QuadPart /= 10000000;  // convert into seconds
 
277
                                        m_server->BlockRemoteInput(true);
 
278
                                }
 
279
                        } else {
 
280
                                GetSystemTime(&systime);
 
281
                                SystemTimeToFileTime(&systime, &ftime);
 
282
                                droptime.LowPart = ftime.dwLowDateTime; 
 
283
                                droptime.HighPart = ftime.dwHighDateTime;
 
284
                                droptime.QuadPart /= 10000000;  // convert into seconds
 
285
                                m_server->BlockRemoteInput(true);
 
286
                        }
 
287
                }
 
288
                else if (msg.message == WM_QUIT)
 
289
                {
 
290
                        break;
 
291
                }
 
292
#ifdef HORIZONLIVE
 
293
                else if (msg.message == LS_QUIT)
 
294
                {
 
295
                        // this is our custom quit message
 
296
                        vnclog.Print(LL_INTINFO, VNCLOG("Received LS_QUIT message.\n"));
 
297
                        break;
 
298
                }
 
299
#endif
 
300
                else
 
301
                {
 
302
                        // Process any other messages normally
 
303
                        DispatchMessage(&msg);
 
304
                }
 
305
 
 
306
                // Check timer to unblock remote input events if necessary
 
307
                // FIXME: rewrite this stuff to eliminate code duplication (ses above).
 
308
                // FIXME: Use time() instead of GetSystemTime().
 
309
                // FIXME: It's not necessary to do this on receiving _each_ message.
 
310
                if (m_server->LocalInputPriority() && droptime.QuadPart != 0) {
 
311
                        GetSystemTime(&systime);
 
312
                        SystemTimeToFileTime(&systime, &ftime);
 
313
                        now.LowPart = ftime.dwLowDateTime;
 
314
                        now.HighPart = ftime.dwHighDateTime;
 
315
                        now.QuadPart /= 10000000;       // convert into seconds
 
316
 
 
317
                        if (now.QuadPart - m_server->DisableTime() >= droptime.QuadPart) {
 
318
                                m_server->BlockRemoteInput(false);
 
319
                                droptime.QuadPart = 0;
 
320
                                m_server->SetKeyboardCounter(0);
 
321
                                m_server->SetMouseCounter(0, msg.pt, false);
 
322
                        }
 
323
                }
 
324
        }
 
325
 
 
326
        m_desktop->SetClipboardActive(FALSE);
 
327
        
 
328
        vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread\n"));
 
329
 
 
330
        // Clear all the hooks and close windows, etc.
 
331
        m_desktop->Shutdown();
 
332
        // Return display settings to previous values.
 
333
        m_desktop->ResetDisplayToNormal();
 
334
        // Turn on the screen.
 
335
        m_desktop->BlankScreen(FALSE);
 
336
 
 
337
        // Clear the shift modifier keys, now that there are no remote clients
 
338
        vncKeymap::ClearShiftKeys();
 
339
 
 
340
        // Switch back into our home desktop, under NT (no effect under 9x)
 
341
        vncService::SelectHDESK(home_desktop);
 
342
 
 
343
        return NULL;
 
344
}
 
345
 
 
346
// Implementation of the vncDesktop class
 
347
 
 
348
vncDesktop::vncDesktop()
 
349
{
 
350
        m_thread = NULL;
 
351
 
 
352
        m_hwnd = NULL;
 
353
        m_polling_flag = FALSE;
 
354
        m_timer_polling = 0;
 
355
        m_timer_blank_screen = 0;
 
356
        m_hnextviewer = NULL;
 
357
        m_hcursor = NULL;
 
358
 
 
359
        m_displaychanged = FALSE;
 
360
 
 
361
        m_hrootdc = NULL;
 
362
        m_hmemdc = NULL;
 
363
        m_membitmap = NULL;
 
364
 
 
365
        m_initialClipBoardSeen = FALSE;
 
366
 
 
367
        // Vars for Will Dean's DIBsection patch
 
368
        m_DIBbits = NULL;
 
369
        m_freemainbuff = FALSE;
 
370
        m_formatmunged = FALSE;
 
371
        m_mainbuff = NULL;
 
372
        m_backbuff = NULL;
 
373
 
 
374
        m_clipboard_active = FALSE;
 
375
        m_hooks_active = FALSE;
 
376
        m_hooks_may_change = FALSE;
 
377
        m_lpAlternateDevMode = NULL;
 
378
        m_copyrect_set = FALSE;
 
379
 
 
380
        m_videodriver = NULL;
 
381
 
 
382
        m_timer_blank_screen = 0;
 
383
}
 
384
 
 
385
vncDesktop::~vncDesktop()
 
386
{
 
387
        vnclog.Print(LL_INTINFO, VNCLOG("killing desktop server\n"));
 
388
 
 
389
        // If we created a thread then here we delete it
 
390
        // The thread itself does most of the cleanup
 
391
        if(m_thread != NULL)
 
392
        {
 
393
                // Post a close message to quit our message handler thread
 
394
                PostMessage(Window(), WM_QUIT, 0, 0);
 
395
 
 
396
                // Join with the desktop handler thread
 
397
                void *returnval;
 
398
                m_thread->join(&returnval);
 
399
                m_thread = NULL;
 
400
        }
 
401
 
 
402
        // Let's call Shutdown just in case something went wrong...
 
403
        Shutdown();
 
404
        _ASSERTE(!m_lpAlternateDevMode);
 
405
}
 
406
 
 
407
// Routine to startup and install all the hooks and stuff
 
408
BOOL
 
409
vncDesktop::Startup()
 
410
{
 
411
#if 0
 
412
        // Currently, we just check whether we're in the console session, and
 
413
        //   fail if not
 
414
        if (!inConsoleSession()) {
 
415
                vnclog.Print(LL_INTERR, VNCLOG("Console is not session zero - reconnect to restore Console session"));
 
416
                return FALSE;
 
417
        }
 
418
#endif
 
419
 
 
420
        // Configure the display for optimal VNC performance.
 
421
        SetupDisplayForConnection();
 
422
 
 
423
        // Initialise the Desktop object
 
424
        if (!InitDesktop())
 
425
                return FALSE;
 
426
 
 
427
        if (InitVideoDriver())
 
428
        {
 
429
// this isn't really necessary
 
430
//              InvalidateRect(NULL,NULL,TRUE);
 
431
        }
 
432
 
 
433
        if (!InitBitmap())
 
434
                return FALSE;
 
435
 
 
436
        if (!ThunkBitmapInfo())
 
437
                return FALSE;
 
438
 
 
439
        if (!SetPixFormat())
 
440
                return FALSE;
 
441
 
 
442
        if (!CreateBuffers())
 
443
                return FALSE;
 
444
 
 
445
        if (!SetPixShifts())
 
446
                return FALSE;
 
447
 
 
448
        if (!SetPalette())
 
449
                return FALSE;
 
450
 
 
451
        if (!InitWindow())
 
452
                return FALSE;
 
453
 
 
454
        // Add the system hook
 
455
        ActivateHooks();
 
456
        m_hooks_may_change = true;
 
457
 
 
458
#ifndef HORIZONLIVE
 
459
        // Start up the keyboard and mouse filters
 
460
        SetKeyboardFilterHook(m_server->LocalInputsDisabled());
 
461
        SetMouseFilterHook(m_server->LocalInputsDisabled());
 
462
#endif
 
463
 
 
464
        // Start up the keyboard and mouse hooks  for 
 
465
        // local event priority over remote impl.
 
466
        if (m_server->LocalInputPriority())
 
467
                SetLocalInputPriorityHook(true);
 
468
 
 
469
        // Start a timer to handle Polling Mode.  The timer will cause
 
470
        // an "idle" event, which is necessary if Polling Mode is being used,
 
471
        // to cause TriggerUpdate to be called.
 
472
        SetPollingFlag(FALSE);
 
473
        SetPollingTimer();
 
474
 
 
475
        // If necessary, start a separate timer to preserve the diplay turned off.
 
476
        UpdateBlankScreenTimer();
 
477
 
 
478
        // Get hold of the WindowPos atom!
 
479
        if ((VNC_WINDOWPOS_ATOM = GlobalAddAtom(VNC_WINDOWPOS_ATOMNAME)) == 0) {
 
480
                vnclog.Print(LL_INTERR, VNCLOG("GlobalAddAtom() failed.\n"));
 
481
                return FALSE;
 
482
        }
 
483
 
 
484
// this member must be initialized: we cant assume the absence
 
485
// of clients when desktop is created.
 
486
        m_cursorpos.left = 0;
 
487
        m_cursorpos.top = 0;
 
488
        m_cursorpos.right = 0;
 
489
        m_cursorpos.bottom = 0;
 
490
 
 
491
        // Everything is ok, so return TRUE
 
492
        return TRUE;
 
493
}
 
494
 
 
495
// Routine to shutdown all the hooks and stuff
 
496
BOOL vncDesktop::Shutdown()
 
497
{
 
498
        // If we created timers then kill them
 
499
        if (m_timer_polling)
 
500
        {
 
501
                KillTimer(Window(), TIMER_POLL);
 
502
                m_timer_polling = 0;
 
503
        }
 
504
        if (m_timer_blank_screen)
 
505
        {
 
506
                KillTimer(Window(), TIMER_BLANK_SCREEN);
 
507
                m_timer_blank_screen = 0;
 
508
        }
 
509
 
 
510
        // If we created a window then kill it and the hooks
 
511
        if (m_hwnd != NULL)
 
512
        {       
 
513
                //Remove the system hooks
 
514
                //Unset keyboard and mouse hooks
 
515
                SetLocalInputPriorityHook(false);
 
516
                m_hooks_may_change = false;
 
517
                ShutdownHooks();
 
518
 
 
519
#ifndef HORIZONLIVE
 
520
                // Stop the keyboard and mouse filters
 
521
                SetKeyboardFilterHook(false);
 
522
                SetMouseFilterHook(false);
 
523
#endif
 
524
                // The window is being closed - remove it from the viewer list
 
525
                ChangeClipboardChain(m_hwnd, m_hnextviewer);
 
526
 
 
527
                // Close the hook window
 
528
                DestroyWindow(m_hwnd);
 
529
                m_hwnd = NULL;
 
530
                m_hnextviewer = NULL;
 
531
        }
 
532
 
 
533
        // Now free all the bitmap stuff
 
534
        if (m_hrootdc != NULL)
 
535
        {
 
536
                // Release our device context
 
537
                if(ReleaseDC(NULL, m_hrootdc) == 0)
 
538
                {
 
539
                        vnclog.Print(LL_INTERR, VNCLOG("failed to ReleaseDC(m_hrootdc)\n"));
 
540
                }
 
541
                m_hrootdc = NULL;
 
542
        }
 
543
        if (m_hmemdc != NULL)
 
544
        {
 
545
                // Release our device context
 
546
                if (!DeleteDC(m_hmemdc))
 
547
                {
 
548
                        vnclog.Print(LL_INTERR, VNCLOG("failed to DeleteDC(m_hmemdc)\n"));
 
549
                }
 
550
                m_hmemdc = NULL;
 
551
        }
 
552
        if (m_membitmap != NULL)
 
553
        {
 
554
                // Release the custom bitmap, if any
 
555
                if (!DeleteObject(m_membitmap))
 
556
                {
 
557
                        vnclog.Print(LL_INTERR, VNCLOG("failed to DeleteObject\n"));
 
558
                }
 
559
                m_membitmap = NULL;
 
560
        }
 
561
 
 
562
        // Free back buffer
 
563
        if (m_backbuff != NULL)
 
564
        {
 
565
                delete [] m_backbuff;
 
566
                m_backbuff = NULL;
 
567
        }
 
568
 
 
569
        if (m_freemainbuff)
 
570
        {
 
571
                // Slow blits were enabled - free the slow blit buffer
 
572
                if (m_mainbuff != NULL)
 
573
                {
 
574
                        delete [] m_mainbuff;
 
575
                        m_mainbuff = NULL;
 
576
                }
 
577
        }
 
578
 
 
579
        // Free the WindowPos atom!
 
580
        if (VNC_WINDOWPOS_ATOM != (ATOM) NULL)
 
581
        {
 
582
                if (GlobalDeleteAtom(VNC_WINDOWPOS_ATOM) != 0)
 
583
                {
 
584
                        vnclog.Print(LL_INTERR, VNCLOG("failed to delete atom!\n"));
 
585
                }
 
586
        }
 
587
 
 
588
        ShutdownVideoDriver();
 
589
 
 
590
        return TRUE;
 
591
}
 
592
 
 
593
// Routines to set/unset hooks via VNCHooks.dll
 
594
 
 
595
void
 
596
vncDesktop::ActivateHooks()
 
597
{
 
598
        BOOL enable = !(m_server->DontSetHooks() && m_server->PollFullScreen());
 
599
        if (enable && !m_hooks_active) {
 
600
                m_hooks_active = SetHook(m_hwnd,
 
601
                                                                 RFB_SCREEN_UPDATE,
 
602
                                                                 RFB_COPYRECT_UPDATE,
 
603
                                                                 RFB_MOUSE_UPDATE);
 
604
                if (!m_hooks_active) {
 
605
                        vnclog.Print(LL_INTERR, VNCLOG("failed to set system hooks\n"));
 
606
                        // Switch on full screen polling, so they can see something, at least...
 
607
                        m_server->PollFullScreen(TRUE);
 
608
                }
 
609
        } else if (!enable) {
 
610
                ShutdownHooks();
 
611
        }
 
612
}
 
613
 
 
614
void
 
615
vncDesktop::ShutdownHooks()
 
616
{
 
617
        if (m_hooks_active)
 
618
                m_hooks_active = !UnSetHook(m_hwnd);
 
619
}
 
620
 
 
621
void
 
622
vncDesktop::TryActivateHooks()
 
623
{
 
624
        if (m_hooks_may_change)
 
625
                ActivateHooks();
 
626
}
 
627
 
 
628
// Routine to ensure we're on the correct NT desktop
 
629
 
 
630
BOOL
 
631
vncDesktop::InitDesktop()
 
632
{
 
633
        if (vncService::InputDesktopSelected())
 
634
                return TRUE;
 
635
 
 
636
        // Ask for the current input desktop
 
637
        return vncService::SelectDesktop(NULL);
 
638
}
 
639
 
 
640
// Routine used to close the screen saver, if it's active...
 
641
 
 
642
BOOL CALLBACK
 
643
KillScreenSaverFunc(HWND hwnd, LPARAM lParam)
 
644
{
 
645
        char buffer[256];
 
646
 
 
647
        // - ONLY try to close Screen-saver windows!!!
 
648
        if ((GetClassName(hwnd, buffer, 256) != 0) &&
 
649
                (strcmp(buffer, "WindowsScreenSaverClass") == 0))
 
650
                PostMessage(hwnd, WM_CLOSE, 0, 0);
 
651
        return TRUE;
 
652
}
 
653
 
 
654
void
 
655
vncDesktop::KillScreenSaver()
 
656
{
 
657
        OSVERSIONINFO osversioninfo;
 
658
        osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
 
659
 
 
660
        // Get the current OS version
 
661
        if (!GetVersionEx(&osversioninfo))
 
662
                return;
 
663
 
 
664
        vnclog.Print(LL_INTINFO, VNCLOG("KillScreenSaver...\n"));
 
665
 
 
666
        // How to kill the screen saver depends on the OS
 
667
        switch (osversioninfo.dwPlatformId)
 
668
        {
 
669
        case VER_PLATFORM_WIN32_WINDOWS:
 
670
                {
 
671
                        // Windows 95
 
672
 
 
673
                        // Fidn the ScreenSaverClass window
 
674
                        HWND hsswnd = FindWindow ("WindowsScreenSaverClass", NULL);
 
675
                        if (hsswnd != NULL)
 
676
                                PostMessage(hsswnd, WM_CLOSE, 0, 0); 
 
677
                        break;
 
678
                } 
 
679
        case VER_PLATFORM_WIN32_NT:
 
680
                {
 
681
                        // Windows NT
 
682
 
 
683
                        // Find the screensaver desktop
 
684
                        HDESK hDesk = OpenDesktop(
 
685
                                "Screen-saver",
 
686
                                0,
 
687
                                FALSE,
 
688
                                DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS
 
689
                                );
 
690
                        if (hDesk != NULL)
 
691
                        {
 
692
                                vnclog.Print(LL_INTINFO, VNCLOG("Killing ScreenSaver\n"));
 
693
 
 
694
                                // Close all windows on the screen saver desktop
 
695
                                EnumDesktopWindows(hDesk, (WNDENUMPROC) &KillScreenSaverFunc, 0);
 
696
                                CloseDesktop(hDesk);
 
697
                                // Pause long enough for the screen-saver to close
 
698
                                //Sleep(2000);
 
699
                                // Reset the screen saver so it can run again
 
700
                                SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, (UINT) TRUE, 0, SPIF_SENDWININICHANGE); 
 
701
                        }
 
702
                        break;
 
703
                }
 
704
        }
 
705
}
 
706
 
 
707
void vncDesktop::ChangeResNow()
 
708
{
 
709
// IMPORTANT: Screen mode alteration may only take place on a single-mon system.
 
710
        if (IsMultiMonDesktop())
 
711
        {
 
712
                return;
 
713
        }
 
714
 
 
715
        BOOL settingsUpdated = false;
 
716
 
 
717
        _ASSERTE(!m_lpAlternateDevMode);
 
718
        m_lpAlternateDevMode = new DEVMODE; // *** create an instance of DEVMODE - Jeremy Peaks
 
719
        if (!m_lpAlternateDevMode)
 
720
        {
 
721
                vnclog.Print(LL_INTINFO, VNCLOG("SCR-WBB: failed to allocate memory "
 
722
                                                                                "for alternate DEVMODE representation!\n"));
 
723
                return;
 
724
        }
 
725
 
 
726
        // *** WBB - Obtain the current display settings.
 
727
        // only on unimon
 
728
        if (! EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, m_lpAlternateDevMode))
 
729
        {
 
730
                vnclog.Print(LL_INTINFO,
 
731
                                         VNCLOG("SCR-WBB: could not get current display settings!\n"));
 
732
                delete m_lpAlternateDevMode;
 
733
                m_lpAlternateDevMode = NULL;
 
734
                return;
 
735
 
 
736
        }
 
737
 
 
738
        vnclog.Print(LL_INTINFO,
 
739
                                 VNCLOG("SCR-WBB: current display: w=%d h=%d bpp=%d vRfrsh=%d.\n"),
 
740
                                 m_lpAlternateDevMode->dmPelsWidth,
 
741
                                 m_lpAlternateDevMode->dmPelsHeight,
 
742
                                 m_lpAlternateDevMode->dmBitsPerPel,
 
743
                                 m_lpAlternateDevMode->dmDisplayFrequency);
 
744
 
 
745
        origPelsWidth = m_lpAlternateDevMode->dmPelsWidth; // *** sets the original resolution for use later
 
746
        origPelsHeight = m_lpAlternateDevMode->dmPelsHeight; // *** - Jeremy Peaks
 
747
 
 
748
        // *** Open the registry key for resolution settings
 
749
        HKEY checkdetails = 0;
 
750
        RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
 
751
                                WINVNC_REGISTRY_KEY,
 
752
                                0,
 
753
                                KEY_READ,
 
754
                                &checkdetails);
 
755
        if (checkdetails)
 
756
        {
 
757
                int slen=MAX_REG_ENTRY_LEN;
 
758
                int valType;
 
759
                char inouttext[MAX_REG_ENTRY_LEN];
 
760
 
 
761
                memset(inouttext, 0, MAX_REG_ENTRY_LEN);
 
762
                
 
763
                // *** Get the registry values for resolution change - Jeremy Peaks
 
764
                RegQueryValueEx(checkdetails,
 
765
                        "ResWidth",
 
766
                        NULL,
 
767
                        (LPDWORD) &valType,
 
768
                        (LPBYTE) &inouttext,
 
769
                        (LPDWORD) &slen);
 
770
 
 
771
                
 
772
                if ((valType == REG_SZ) &&
 
773
                        atol(inouttext)) { // *** if width is 0, then this isn't a valid resolution, so do nothing - Jeremy Peaks
 
774
                        m_lpAlternateDevMode->dmPelsWidth = atol(inouttext);
 
775
 
 
776
                        memset(inouttext, 0, MAX_REG_ENTRY_LEN);
 
777
 
 
778
                        RegQueryValueEx(checkdetails,
 
779
                                "ResHeight",
 
780
                                NULL,
 
781
                                (LPDWORD) &valType,
 
782
                                (LPBYTE) &inouttext,
 
783
                                (LPDWORD) &slen);
 
784
                        
 
785
                        m_lpAlternateDevMode->dmPelsHeight = atol(inouttext);
 
786
                        if ((valType == REG_SZ ) &&
 
787
                                (m_lpAlternateDevMode->dmPelsHeight > 0)) {
 
788
 
 
789
                                vnclog.Print(LL_INTINFO,
 
790
                                        VNCLOG("SCR-WBB: attempting to change "
 
791
                                                   "resolution w=%d h=%d\n"),
 
792
                                        m_lpAlternateDevMode->dmPelsWidth,
 
793
                                        m_lpAlternateDevMode->dmPelsHeight);
 
794
 
 
795
                                // *** make res change - Jeremy Peaks
 
796
                                // testing: predefined Width/Height may become incompatible
 
797
                                // with new clrdepth/timings
 
798
                                long resultOfResChange = ChangeDisplaySettings(m_lpAlternateDevMode, CDS_TEST);
 
799
                                if (resultOfResChange == DISP_CHANGE_SUCCESSFUL) {
 
800
                                        ChangeDisplaySettings(m_lpAlternateDevMode, CDS_UPDATEREGISTRY);
 
801
                                        settingsUpdated = true;
 
802
                                }
 
803
                        } 
 
804
                }
 
805
 
 
806
                RegCloseKey(checkdetails);
 
807
        }
 
808
 
 
809
        if (! settingsUpdated)
 
810
        {
 
811
// Did not change the resolution.
 
812
                delete m_lpAlternateDevMode;
 
813
                m_lpAlternateDevMode = NULL;
 
814
        }
 
815
}
 
816
 
 
817
void
 
818
vncDesktop::SetupDisplayForConnection()
 
819
{
 
820
        KillScreenSaver();
 
821
 
 
822
        ChangeResNow(); // *** - Jeremy Peaks
 
823
}
 
824
 
 
825
void
 
826
vncDesktop::ResetDisplayToNormal()
 
827
{
 
828
        if (m_lpAlternateDevMode != NULL)
 
829
        {
 
830
                // *** In case the resolution was changed, revert to original settings now
 
831
                m_lpAlternateDevMode->dmPelsWidth = origPelsWidth;
 
832
                m_lpAlternateDevMode->dmPelsHeight = origPelsHeight;
 
833
 
 
834
                long resultOfResChange = ChangeDisplaySettings(m_lpAlternateDevMode, CDS_TEST);
 
835
                if (resultOfResChange == DISP_CHANGE_SUCCESSFUL)
 
836
                        ChangeDisplaySettings(m_lpAlternateDevMode, CDS_UPDATEREGISTRY);
 
837
 
 
838
                delete m_lpAlternateDevMode;
 
839
                m_lpAlternateDevMode = NULL;
 
840
        }
 
841
}
 
842
 
 
843
RECT vncDesktop::GetSourceRect()
 
844
{
 
845
        if (m_server->WindowShared())
 
846
        {
 
847
                RECT wrect;
 
848
                GetWindowRect(m_server->GetWindowShared(), &wrect);
 
849
                return wrect;
 
850
        }
 
851
        else if (m_server->ScreenAreaShared())
 
852
        {
 
853
                return m_server->GetScreenAreaRect();
 
854
        }
 
855
        else if (m_server->PrimaryDisplayOnlyShared())
 
856
        {
 
857
                RECT pdr = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };
 
858
                return pdr;
 
859
        }
 
860
        else
 
861
        {
 
862
#ifdef _DEBUG
 
863
                RECT rd;
 
864
                _ASSERTE(GetSourceDisplayRect(rd));
 
865
                _ASSERTE(EqualRect(&rd, &m_bmrect));
 
866
#endif
 
867
                return m_bmrect;
 
868
        }
 
869
}
 
870
 
 
871
RECT    GetScreenRect()
 
872
{
 
873
        RECT screenrect;
 
874
        if (IsWinVerOrHigher(4, 10))
 
875
        {
 
876
                screenrect.left         = GetSystemMetrics(SM_XVIRTUALSCREEN);
 
877
                screenrect.top          = GetSystemMetrics(SM_YVIRTUALSCREEN);
 
878
                screenrect.right        = screenrect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
 
879
                screenrect.bottom       = screenrect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
 
880
        }
 
881
        else
 
882
        {
 
883
                screenrect.left = 0;
 
884
                screenrect.top = 0;
 
885
                screenrect.right = GetSystemMetrics(SM_CXSCREEN);
 
886
                screenrect.bottom = GetSystemMetrics(SM_CYSCREEN);
 
887
        }
 
888
        return screenrect;
 
889
}
 
890
 
 
891
BOOL vncDesktop::GetSourceDisplayRect(RECT &rdisp_rect)
 
892
{
 
893
        if (!m_hrootdc)
 
894
                m_hrootdc = ::GetDC(NULL);
 
895
        if (!m_hrootdc)
 
896
        {
 
897
                vnclog.Print(LL_INTERR, VNCLOG("GetDC() failed, error=%d\n"), GetLastError());
 
898
                return FALSE;
 
899
        }
 
900
 
 
901
// TODO: refactor it
 
902
        rdisp_rect = GetScreenRect();
 
903
        return TRUE;
 
904
}
 
905
 
 
906
BOOL vncDesktop::InitBitmap()
 
907
{
 
908
// IMPORTANT: here an optimization may be implemented
 
909
// when only a fixed rect is shared.
 
910
// then m_bmrect should be set to that rect.
 
911
        if (!GetSourceDisplayRect(m_bmrect))
 
912
        {
 
913
                return FALSE;
 
914
        }
 
915
 
 
916
        vnclog.Print(
 
917
                LL_INTINFO,
 
918
                VNCLOG("source desktop metrics: (%d, %d, %d, %d)\n"),
 
919
                m_bmrect.left,
 
920
                m_bmrect.top,
 
921
                m_bmrect.right,
 
922
                m_bmrect.bottom);
 
923
 
 
924
        vnclog.Print(
 
925
                LL_INTINFO,
 
926
                VNCLOG("bitmap dimensions are %dx%d\n"),
 
927
                m_bmrect.right - m_bmrect.left,
 
928
                m_bmrect.bottom - m_bmrect.top);
 
929
 
 
930
        // Create a compatible memory DC
 
931
        m_hmemdc = CreateCompatibleDC(m_hrootdc);
 
932
        if (m_hmemdc == NULL) {
 
933
                vnclog.Print(LL_INTERR, VNCLOG("CreateCompatibleDC() failed, error=%d\n"),
 
934
                                         GetLastError());
 
935
                return FALSE;
 
936
        }
 
937
 
 
938
        // Check that the device capabilities are ok
 
939
        if ((GetDeviceCaps(m_hrootdc, RASTERCAPS) & RC_BITBLT) == 0)
 
940
        {
 
941
// FIXME: MessageBox in a service
 
942
                MessageBox(
 
943
                        NULL,
 
944
                        "vncDesktop : root device doesn't support BitBlt\n"
 
945
                        "WinVNC cannot be used with this graphic device driver",
 
946
                        szAppName,
 
947
                        MB_ICONSTOP | MB_OK
 
948
                        );
 
949
                return FALSE;
 
950
        }
 
951
        if ((GetDeviceCaps(m_hmemdc, RASTERCAPS) & RC_DI_BITMAP) == 0)
 
952
        {
 
953
// FIXME: MessageBox in a service
 
954
                MessageBox(
 
955
                        NULL,
 
956
                        "vncDesktop : memory device doesn't support GetDIBits\n"
 
957
                        "WinVNC cannot be used with this graphics device driver",
 
958
                        szAppName,
 
959
                        MB_ICONSTOP | MB_OK
 
960
                        );
 
961
                return FALSE;
 
962
        }
 
963
 
 
964
        // Create the bitmap to be compatible with the ROOT DC!!!
 
965
        m_membitmap = CreateCompatibleBitmap(
 
966
                m_hrootdc,
 
967
                m_bmrect.right - m_bmrect.left,
 
968
                m_bmrect.bottom - m_bmrect.top);
 
969
        if (m_membitmap == NULL)
 
970
        {
 
971
                vnclog.Print(
 
972
                        LL_INTERR,
 
973
                        VNCLOG("failed to create memory bitmap, error=%d\n"),
 
974
                        GetLastError());
 
975
                return FALSE;
 
976
        }
 
977
        vnclog.Print(LL_INTINFO, VNCLOG("created memory bitmap\n"));
 
978
 
 
979
        // Get the bitmap's format and colour details
 
980
        int result;
 
981
        m_bminfo.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 
982
        m_bminfo.bmi.bmiHeader.biBitCount = 0;
 
983
        result = ::GetDIBits(m_hmemdc, m_membitmap, 0, 1, NULL, &m_bminfo.bmi, DIB_RGB_COLORS);
 
984
        if (result == 0) {
 
985
                return FALSE;
 
986
        }
 
987
        result = ::GetDIBits(m_hmemdc, m_membitmap, 0, 1, NULL, &m_bminfo.bmi, DIB_RGB_COLORS);
 
988
        if (result == 0) {
 
989
                return FALSE;
 
990
        }
 
991
        vnclog.Print(LL_INTINFO, VNCLOG("got bitmap format\n"));
 
992
        vnclog.Print(LL_INTINFO, VNCLOG("DBG:display context has %d planes!\n"), GetDeviceCaps(m_hrootdc, PLANES));
 
993
        vnclog.Print(LL_INTINFO, VNCLOG("DBG:memory context has %d planes!\n"), GetDeviceCaps(m_hmemdc, PLANES));
 
994
        if (GetDeviceCaps(m_hmemdc, PLANES) != 1)
 
995
        {
 
996
// FIXME: MessageBox in a service
 
997
                MessageBox(
 
998
                        NULL,
 
999
                        "vncDesktop : current display is PLANAR, not CHUNKY!\n"
 
1000
                        "WinVNC cannot be used with this graphics device driver",
 
1001
                        szAppName,
 
1002
                        MB_ICONSTOP | MB_OK
 
1003
                        );
 
1004
                return FALSE;
 
1005
        }
 
1006
 
 
1007
        // Henceforth we want to use a top-down scanning representation
 
1008
        m_bminfo.bmi.bmiHeader.biHeight = - abs(m_bminfo.bmi.bmiHeader.biHeight);
 
1009
 
 
1010
        // Is the bitmap palette-based or truecolour?
 
1011
        m_bminfo.truecolour = (GetDeviceCaps(m_hmemdc, RASTERCAPS) & RC_PALETTE) == 0;
 
1012
 
 
1013
        return TRUE;
 
1014
}
 
1015
 
 
1016
 
 
1017
BOOL
 
1018
vncDesktop::ThunkBitmapInfo()
 
1019
{
 
1020
        // If we leave the pixel format intact, the blits can be optimised (Will Dean's patch)
 
1021
        m_formatmunged = FALSE;
 
1022
 
 
1023
        // HACK ***.  Optimised blits don't work with palette-based displays, yet
 
1024
        if (!m_bminfo.truecolour) {
 
1025
                m_formatmunged = TRUE;
 
1026
        }
 
1027
 
 
1028
        // Attempt to force the actual format into one we can handle
 
1029
        // We can handle 8-bit-palette and 16/32-bit-truecolour modes
 
1030
        switch (m_bminfo.bmi.bmiHeader.biBitCount)
 
1031
        {
 
1032
        case 1:
 
1033
        case 4:
 
1034
                vnclog.Print(LL_INTINFO, VNCLOG("DBG:used/bits/planes/comp/size "
 
1035
                                                                                "= %d/%d/%d/%d/%d\n"),
 
1036
                                         (int)m_bminfo.bmi.bmiHeader.biClrUsed,
 
1037
                                         (int)m_bminfo.bmi.bmiHeader.biBitCount,
 
1038
                                         (int)m_bminfo.bmi.bmiHeader.biPlanes,
 
1039
                                         (int)m_bminfo.bmi.bmiHeader.biCompression,
 
1040
                                         (int)m_bminfo.bmi.bmiHeader.biSizeImage);
 
1041
                
 
1042
                // Correct the BITMAPINFO header to the format we actually want
 
1043
                m_bminfo.bmi.bmiHeader.biClrUsed = 0;
 
1044
                m_bminfo.bmi.bmiHeader.biPlanes = 1;
 
1045
                m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;
 
1046
                m_bminfo.bmi.bmiHeader.biBitCount = 8;
 
1047
                m_bminfo.bmi.bmiHeader.biSizeImage =
 
1048
                        abs((m_bminfo.bmi.bmiHeader.biWidth *
 
1049
                                m_bminfo.bmi.bmiHeader.biHeight *
 
1050
                                m_bminfo.bmi.bmiHeader.biBitCount)/ 8);
 
1051
                m_bminfo.bmi.bmiHeader.biClrImportant = 0;
 
1052
                m_bminfo.truecolour = FALSE;
 
1053
 
 
1054
                // Display format is non-VNC compatible - use the slow blit method
 
1055
                m_formatmunged = TRUE;
 
1056
                break;  
 
1057
        case 24:
 
1058
                // Update the bitmapinfo header
 
1059
                m_bminfo.bmi.bmiHeader.biBitCount = 32;
 
1060
                m_bminfo.bmi.bmiHeader.biPlanes = 1;
 
1061
                m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;
 
1062
                m_bminfo.bmi.bmiHeader.biSizeImage =
 
1063
                        abs((m_bminfo.bmi.bmiHeader.biWidth *
 
1064
                                m_bminfo.bmi.bmiHeader.biHeight *
 
1065
                                m_bminfo.bmi.bmiHeader.biBitCount)/ 8);
 
1066
                // Display format is non-VNC compatible - use the slow blit method
 
1067
                m_formatmunged = TRUE;
 
1068
                break;
 
1069
        }
 
1070
 
 
1071
        return TRUE;
 
1072
}
 
1073
 
 
1074
BOOL
 
1075
vncDesktop::SetPixFormat()
 
1076
{
 
1077
        // Examine the bitmapinfo structure to obtain the current pixel format
 
1078
        m_scrinfo.format.trueColour = m_bminfo.truecolour;
 
1079
        m_scrinfo.format.bigEndian = 0;
 
1080
 
 
1081
        // Set up the native buffer width, height and format
 
1082
        m_scrinfo.framebufferWidth = (CARD16) (m_bmrect.right - m_bmrect.left);         // Swap endian before actually sending
 
1083
        m_scrinfo.framebufferHeight = (CARD16) (m_bmrect.bottom - m_bmrect.top);        // Swap endian before actually sending
 
1084
        m_scrinfo.format.bitsPerPixel = (CARD8) m_bminfo.bmi.bmiHeader.biBitCount;
 
1085
        m_scrinfo.format.depth        = (CARD8) m_bminfo.bmi.bmiHeader.biBitCount;
 
1086
 
 
1087
        
 
1088
        // Calculate the number of bytes per row
 
1089
        m_bytesPerRow = m_scrinfo.framebufferWidth * m_scrinfo.format.bitsPerPixel / 8;
 
1090
 
 
1091
        return TRUE;
 
1092
}
 
1093
 
 
1094
BOOL
 
1095
vncDesktop::SetPixShifts()
 
1096
{
 
1097
        // Sort out the colour shifts, etc.
 
1098
        DWORD redMask=0, blueMask=0, greenMask = 0;
 
1099
 
 
1100
        switch (m_bminfo.bmi.bmiHeader.biBitCount)
 
1101
        {
 
1102
        case 16:
 
1103
                if (m_videodriver&& m_videodriver->IsDirectAccessInEffect())
 
1104
                {
 
1105
// IMPORTANT: Mirage colormask is always 565
 
1106
                        redMask = 0xf800;
 
1107
                        greenMask = 0x07e0;
 
1108
                        blueMask = 0x001f;
 
1109
                }
 
1110
                else if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)
 
1111
                {
 
1112
                // Standard 16-bit display
 
1113
                // each word single pixel 5-5-5
 
1114
                        redMask = 0x7c00; greenMask = 0x03e0; blueMask = 0x001f;
 
1115
                }
 
1116
                else
 
1117
                {
 
1118
                        if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)
 
1119
                        {
 
1120
                                redMask =   *(DWORD *) &m_bminfo.bmi.bmiColors[0];
 
1121
                                greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
 
1122
                                blueMask =  *(DWORD *) &m_bminfo.bmi.bmiColors[2];
 
1123
                        }
 
1124
                }
 
1125
                break;
 
1126
 
 
1127
        case 32:
 
1128
                // Standard 24/32 bit displays
 
1129
                if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB ||
 
1130
                        m_videodriver && m_videodriver->IsDirectAccessInEffect())
 
1131
                {
 
1132
                        redMask = 0xff0000;
 
1133
                        greenMask = 0xff00;
 
1134
                        blueMask = 0x00ff;
 
1135
 
 
1136
                        // The real color depth is 24 bits in this case. If the depth
 
1137
                        // is set to 32, the Tight encoder shows worse performance.
 
1138
                        m_scrinfo.format.depth = 24;
 
1139
                }
 
1140
                else
 
1141
                {
 
1142
                        if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)
 
1143
                        {
 
1144
                                redMask =   *(DWORD *) &m_bminfo.bmi.bmiColors[0];
 
1145
                                greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
 
1146
                                blueMask =  *(DWORD *) &m_bminfo.bmi.bmiColors[2];
 
1147
                        }
 
1148
                }
 
1149
                break;
 
1150
 
 
1151
        default:
 
1152
                // Other pixel formats are only valid if they're palette-based
 
1153
                if (m_bminfo.truecolour)
 
1154
                {
 
1155
                        vnclog.Print(LL_INTERR, "unsupported truecolour pixel format for SetPixShifts()\n");
 
1156
                        return FALSE;
 
1157
                }
 
1158
                vnclog.Print(LL_INTINFO, VNCLOG("DBG:palette-based desktop in SetPixShifts()\n"));
 
1159
                return TRUE;
 
1160
        }
 
1161
 
 
1162
        // Convert the data we just retrieved
 
1163
        MaskToMaxAndShift(redMask, m_scrinfo.format.redMax, m_scrinfo.format.redShift);
 
1164
        MaskToMaxAndShift(greenMask, m_scrinfo.format.greenMax, m_scrinfo.format.greenShift);
 
1165
        MaskToMaxAndShift(blueMask, m_scrinfo.format.blueMax, m_scrinfo.format.blueShift);
 
1166
 
 
1167
        vnclog.Print(LL_INTINFO, VNCLOG("DBG:true-color desktop in SetPixShifts()\n"));
 
1168
        return TRUE;
 
1169
}
 
1170
 
 
1171
BOOL
 
1172
vncDesktop::SetPalette()
 
1173
{
 
1174
        // Lock the current display palette into the memory DC we're holding
 
1175
        // *** CHECK THIS FOR LEAKS!
 
1176
        if (!m_bminfo.truecolour)
 
1177
        {
 
1178
                LOGPALETTE *palette;
 
1179
                UINT size = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
 
1180
 
 
1181
                palette = (LOGPALETTE *) new char[size];
 
1182
                if (palette == NULL) {
 
1183
                        vnclog.Print(LL_INTERR, VNCLOG("error allocating palette\n"));
 
1184
                        return FALSE;
 
1185
                }
 
1186
 
 
1187
                // Initialise the structure
 
1188
                palette->palVersion = 0x300;
 
1189
                palette->palNumEntries = 256;
 
1190
 
 
1191
                // Get the system colours
 
1192
                if (GetSystemPaletteEntries(m_hrootdc, 0, 256, palette->palPalEntry) == 0)
 
1193
                {
 
1194
                        vnclog.Print(LL_INTERR, VNCLOG("GetSystemPaletteEntries() failed.\n"));
 
1195
                        delete [] palette;
 
1196
                        return FALSE;
 
1197
                }
 
1198
 
 
1199
                // Create a palette from those
 
1200
                HPALETTE pal = CreatePalette(palette);
 
1201
                if (pal == NULL)
 
1202
                {
 
1203
                        vnclog.Print(LL_INTERR, VNCLOG("CreatePalette() failed.\n"));
 
1204
                        delete [] palette;
 
1205
                        return FALSE;
 
1206
                }
 
1207
 
 
1208
                // Select the palette into our memory DC
 
1209
                HPALETTE oldpalette = SelectPalette(m_hmemdc, pal, FALSE);
 
1210
                if (oldpalette == NULL)
 
1211
                {
 
1212
                        vnclog.Print(LL_INTERR, VNCLOG("SelectPalette() failed.\n"));
 
1213
                        delete [] palette;
 
1214
                        DeleteObject(pal);
 
1215
                        return FALSE;
 
1216
                }
 
1217
 
 
1218
                // Worked, so realise the palette
 
1219
                if (RealizePalette(m_hmemdc) == GDI_ERROR)
 
1220
                        vnclog.Print(LL_INTWARN, VNCLOG("warning - failed to RealizePalette\n"));
 
1221
 
 
1222
                // It worked!
 
1223
                delete [] palette;
 
1224
                DeleteObject(oldpalette);
 
1225
 
 
1226
                vnclog.Print(LL_INTINFO, VNCLOG("initialised palette OK\n"));
 
1227
                return TRUE;
 
1228
        }
 
1229
 
 
1230
        // Not a palette based local screen - forget it!
 
1231
        vnclog.Print(LL_INTINFO, VNCLOG("no palette data for truecolour display\n"));
 
1232
        return TRUE;
 
1233
}
 
1234
 
 
1235
LRESULT CALLBACK DesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
 
1236
 
 
1237
ATOM m_wndClass = 0;
 
1238
 
 
1239
BOOL
 
1240
vncDesktop::InitWindow()
 
1241
{
 
1242
        if (m_wndClass == 0) {
 
1243
                // Create the window class
 
1244
                WNDCLASSEX wndclass;
 
1245
 
 
1246
                wndclass.cbSize                 = sizeof(wndclass);
 
1247
                wndclass.style                  = 0;
 
1248
                wndclass.lpfnWndProc    = &DesktopWndProc;
 
1249
                wndclass.cbClsExtra             = 0;
 
1250
                wndclass.cbWndExtra             = 0;
 
1251
                wndclass.hInstance              = hAppInstance;
 
1252
                wndclass.hIcon                  = NULL;
 
1253
                wndclass.hCursor                = NULL;
 
1254
                wndclass.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
 
1255
                wndclass.lpszMenuName   = (const char *) NULL;
 
1256
                wndclass.lpszClassName  = szDesktopSink;
 
1257
                wndclass.hIconSm                = NULL;
 
1258
 
 
1259
                // Register it
 
1260
                m_wndClass = RegisterClassEx(&wndclass);
 
1261
        }
 
1262
 
 
1263
        // And create a window
 
1264
        m_hwnd = CreateWindow(szDesktopSink,
 
1265
                                "WinVNC",
 
1266
                                WS_OVERLAPPEDWINDOW,
 
1267
                                CW_USEDEFAULT,
 
1268
                                CW_USEDEFAULT,
 
1269
                                400, 200,
 
1270
                                NULL,
 
1271
                                NULL,
 
1272
                                hAppInstance,
 
1273
                                NULL);
 
1274
 
 
1275
        if (m_hwnd == NULL) {
 
1276
                vnclog.Print(LL_INTERR, VNCLOG("CreateWindow() failed.\n"));
 
1277
                return FALSE;
 
1278
        }
 
1279
 
 
1280
        // Set the "this" pointer for the window
 
1281
        SetWindowLong(m_hwnd, GWL_USERDATA, (long)this);
 
1282
 
 
1283
        // Enable clipboard hooking
 
1284
        m_hnextviewer = SetClipboardViewer(m_hwnd);
 
1285
 
 
1286
        return TRUE;
 
1287
}
 
1288
 
 
1289
BOOL
 
1290
vncDesktop::CreateBuffers()
 
1291
{
 
1292
        vnclog.Print(LL_INTINFO, VNCLOG("attempting to create main and back buffers\n"));
 
1293
 
 
1294
        // Create a new DIB section ***
 
1295
        HBITMAP tempbitmap = NULL;
 
1296
        if (!m_formatmunged)
 
1297
        {
 
1298
                tempbitmap = CreateDIBSection(
 
1299
                        m_hmemdc,
 
1300
                        &m_bminfo.bmi,
 
1301
                        DIB_RGB_COLORS,
 
1302
                        &m_DIBbits,
 
1303
                        NULL,
 
1304
                        0);
 
1305
                if (tempbitmap == NULL)
 
1306
                {
 
1307
                        vnclog.Print(LL_INTWARN, VNCLOG("failed to build DIB section - reverting to slow blits\n"));
 
1308
                }
 
1309
        }
 
1310
 
 
1311
        m_freemainbuff = false;
 
1312
 
 
1313
// NOTE m_mainbuff and m_backbuff allocation can not be supressed
 
1314
// even with direct access mirror surface view
 
1315
 
 
1316
        if (tempbitmap == NULL)
 
1317
        {
 
1318
                m_DIBbits = NULL;
 
1319
                // create our own buffer to copy blits through
 
1320
                if ((m_mainbuff = new BYTE [ScreenBuffSize()]) == NULL) {
 
1321
                                vnclog.Print(LL_INTERR, VNCLOG("unable to allocate main buffer[%d]\n"), ScreenBuffSize());
 
1322
                                return FALSE;
 
1323
                }
 
1324
                m_freemainbuff = true;
 
1325
                if ((m_backbuff = new BYTE [ScreenBuffSize()]) == NULL) {
 
1326
                        vnclog.Print(LL_INTERR, VNCLOG("unable to allocate back buffer[%d]\n"), ScreenBuffSize());
 
1327
                        return FALSE;
 
1328
                }
 
1329
                return TRUE;
 
1330
        }
 
1331
        
 
1332
        // Create our own buffer to copy blits through
 
1333
        if ((m_backbuff = new BYTE [ScreenBuffSize()]) == NULL) {
 
1334
                vnclog.Print(LL_INTERR, VNCLOG("unable to allocate back buffer[%d]\n"), ScreenBuffSize());
 
1335
                if (tempbitmap!= NULL)
 
1336
                        DeleteObject(tempbitmap);
 
1337
                return FALSE;
 
1338
        }
 
1339
 
 
1340
        // Delete the old memory bitmap
 
1341
        if (m_membitmap != NULL) {
 
1342
                DeleteObject(m_membitmap);
 
1343
                m_membitmap = NULL;
 
1344
        }
 
1345
 
 
1346
        // Replace old membitmap with DIB section
 
1347
        m_membitmap = tempbitmap;
 
1348
        m_mainbuff = (BYTE *)m_DIBbits;
 
1349
        vnclog.Print(LL_INTINFO, VNCLOG("enabled fast DIBsection blits OK\n"));
 
1350
        return TRUE;
 
1351
}
 
1352
 
 
1353
BOOL
 
1354
vncDesktop::Init(vncServer *server)
 
1355
{
 
1356
        vnclog.Print(LL_INTINFO, VNCLOG("initialising desktop server\n"));
 
1357
 
 
1358
        // Save the server pointer
 
1359
        m_server = server;
 
1360
 
 
1361
        // Load in the arrow cursor
 
1362
        m_hdefcursor = LoadCursor(NULL, IDC_ARROW);
 
1363
        m_hcursor = m_hdefcursor;
 
1364
 
 
1365
        // Spawn a thread to handle that window's message queue
 
1366
        vncDesktopThread *thread = new vncDesktopThread;
 
1367
        if (thread == NULL)
 
1368
                return FALSE;
 
1369
        m_thread = thread;
 
1370
        return thread->Init(this, m_server);
 
1371
}
 
1372
 
 
1373
void
 
1374
vncDesktop::RequestUpdate()
 
1375
{
 
1376
        PostMessage(m_hwnd, WM_TIMER, TIMER_POLL, 0);
 
1377
}
 
1378
 
 
1379
int
 
1380
vncDesktop::ScreenBuffSize()
 
1381
{
 
1382
        return m_scrinfo.format.bitsPerPixel/8 *
 
1383
                m_scrinfo.framebufferWidth *
 
1384
                m_scrinfo.framebufferHeight;
 
1385
}
 
1386
 
 
1387
void
 
1388
vncDesktop::FillDisplayInfo(rfbServerInitMsg *scrinfo)
 
1389
{
 
1390
        memcpy(scrinfo, &m_scrinfo, sz_rfbServerInitMsg);
 
1391
}
 
1392
 
 
1393
// Function to capture an area of the screen immediately prior to sending
 
1394
// an update.
 
1395
 
 
1396
void vncDesktop::CaptureScreen(const RECT &UpdateArea, BYTE *scrBuff)
 
1397
{
 
1398
// ASSUME rect related to virtual desktop
 
1399
        if (m_videodriver && m_videodriver->IsDirectAccessInEffect())
 
1400
                        CaptureScreenFromMirage(UpdateArea, scrBuff);
 
1401
        else    CaptureScreenFromAdapterGeneral(UpdateArea, scrBuff);
 
1402
}
 
1403
 
 
1404
void vncDesktop::CaptureScreenFromAdapterGeneral(RECT rect, BYTE *scrBuff)
 
1405
{
 
1406
// ASSUME rect related to virtual desktop
 
1407
        // Protect the memory bitmap
 
1408
        omni_mutex_lock l(m_bitbltlock);
 
1409
 
 
1410
        // Finish drawing anything in this thread 
 
1411
        // Wish we could do this for the whole system - maybe we should
 
1412
        // do something with LockWindowUpdate here.
 
1413
        GdiFlush();
 
1414
 
 
1415
        // Select the memory bitmap into the memory DC
 
1416
        HBITMAP oldbitmap;
 
1417
        if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL)
 
1418
                return;
 
1419
 
 
1420
        // Capture screen into bitmap
 
1421
        BOOL blitok = BitBlt(
 
1422
                m_hmemdc,
 
1423
// source in m_hrootdc is relative to a virtual desktop,
 
1424
// whereas dst coordinates of m_hmemdc are relative to its top-left corner (0, 0)
 
1425
                rect.left - m_bmrect.left,
 
1426
                rect.top - m_bmrect.top,
 
1427
                rect.right - rect.left,
 
1428
                rect.bottom - rect.top,
 
1429
                m_hrootdc,
 
1430
                rect.left, rect.top,
 
1431
                SRCCOPY);
 
1432
 
 
1433
        // Select the old bitmap back into the memory DC
 
1434
        SelectObject(m_hmemdc, oldbitmap);
 
1435
        
 
1436
        if (blitok)
 
1437
        {
 
1438
        // Copy the new data to the screen buffer (CopyToBuffer optimises this if possible)
 
1439
                CopyToBuffer(rect, scrBuff);
 
1440
        }
 
1441
 
 
1442
}
 
1443
 
 
1444
void vncDesktop::CaptureScreenFromMirage(RECT UpdateArea, BYTE *scrBuff)
 
1445
{
 
1446
// ASSUME rect related to virtual desktop
 
1447
        _ASSERTE(m_videodriver);
 
1448
        omni_mutex_lock l(m_bitbltlock);
 
1449
        CopyToBuffer(UpdateArea, scrBuff, m_videodriver->GetScreenView());
 
1450
}
 
1451
 
 
1452
void    vncDesktop::CaptureMouseRect()
 
1453
{
 
1454
        POINT CursorPos;
 
1455
        ICONINFO IconInfo;
 
1456
 
 
1457
        // If the mouse cursor handle is invalid then forget it
 
1458
        if (m_hcursor == NULL)
 
1459
                return;
 
1460
 
 
1461
        // Get the cursor position
 
1462
        if (!GetCursorPos(&CursorPos))
 
1463
                return;
 
1464
 
 
1465
        // Translate position for hotspot
 
1466
        if (GetIconInfo(m_hcursor, &IconInfo))
 
1467
        {
 
1468
                CursorPos.x -= ((int) IconInfo.xHotspot);
 
1469
                CursorPos.y -= ((int) IconInfo.yHotspot);
 
1470
 
 
1471
                if (IconInfo.hbmMask != NULL)
 
1472
                        DeleteObject(IconInfo.hbmMask);
 
1473
                if (IconInfo.hbmColor != NULL)
 
1474
                        DeleteObject(IconInfo.hbmColor);
 
1475
        }
 
1476
 
 
1477
        // Save the bounding rectangle
 
1478
        m_cursorpos.left = CursorPos.x;
 
1479
        m_cursorpos.top = CursorPos.y;
 
1480
        m_cursorpos.right = CursorPos.x + GetSystemMetrics(SM_CXCURSOR);
 
1481
        m_cursorpos.bottom = CursorPos.y + GetSystemMetrics(SM_CYCURSOR);
 
1482
}
 
1483
 
 
1484
// Add the mouse pointer to the buffer
 
1485
void vncDesktop::CaptureMouse(BYTE *scrBuff, UINT scrBuffSize)
 
1486
{
 
1487
        // Protect the memory bitmap
 
1488
        omni_mutex_lock l(m_bitbltlock);
 
1489
 
 
1490
        CaptureMouseRect();
 
1491
 
 
1492
        // Select the memory bitmap into the memory DC
 
1493
        HBITMAP oldbitmap;
 
1494
        if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL)
 
1495
                return;
 
1496
 
 
1497
        // Draw the cursor
 
1498
        DrawIconEx(
 
1499
                m_hmemdc,                                                                       // handle to device context 
 
1500
                m_cursorpos.left - m_bmrect.left,
 
1501
                m_cursorpos.top - m_bmrect.top,
 
1502
                m_hcursor,                                                                      // handle to icon to draw 
 
1503
                0,0,                                                                            // width of the icon 
 
1504
                0,                                                                                      // index of frame in animated cursor 
 
1505
                NULL,                                                                           // handle to background brush 
 
1506
                DI_NORMAL                                                                       // icon-drawing flags 
 
1507
                );
 
1508
 
 
1509
        // Select the old bitmap back into the memory DC
 
1510
        SelectObject(m_hmemdc, oldbitmap);
 
1511
 
 
1512
        // Clip the bounding rect to the screen
 
1513
        RECT screen = m_server->GetSharedRect();
 
1514
        // Copy the mouse cursor into the screen buffer, if any of it is visible
 
1515
        if (IntersectRect(&m_cursorpos, &m_cursorpos, &screen))
 
1516
                CopyToBuffer(m_cursorpos, scrBuff);
 
1517
}
 
1518
 
 
1519
// Obtain cursor image data in server's local format.
 
1520
// The length of databuf[] should be at least (width * height * 4).
 
1521
BOOL
 
1522
vncDesktop::GetRichCursorData(BYTE *databuf, HCURSOR hcursor, int width, int height)
 
1523
{
 
1524
        // Protect the memory bitmap (is it really necessary here?)
 
1525
        omni_mutex_lock l(m_bitbltlock);
 
1526
 
 
1527
        // Create bitmap, select it into memory DC
 
1528
        HBITMAP membitmap = CreateCompatibleBitmap(m_hrootdc, width, height);
 
1529
        if (membitmap == NULL) {
 
1530
                return FALSE;
 
1531
        }
 
1532
        HBITMAP oldbitmap = (HBITMAP) SelectObject(m_hmemdc, membitmap);
 
1533
        if (oldbitmap == NULL) {
 
1534
                DeleteObject(membitmap);
 
1535
                return FALSE;
 
1536
        }
 
1537
 
 
1538
        // Draw the cursor
 
1539
        DrawIconEx(m_hmemdc, 0, 0, hcursor, 0, 0, 0, NULL, DI_IMAGE);
 
1540
        SelectObject(m_hmemdc, oldbitmap);
 
1541
 
 
1542
        // Prepare BITMAPINFO structure (copy most m_bminfo fields)
 
1543
        BITMAPINFO *bmi = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
 
1544
        memcpy(bmi, &m_bminfo.bmi, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
 
1545
        bmi->bmiHeader.biWidth = width;
 
1546
        bmi->bmiHeader.biHeight = -height;
 
1547
 
 
1548
        // Clear data buffer and extract RGB data
 
1549
        memset(databuf, 0x00, width * height * 4);
 
1550
        int lines = GetDIBits(m_hmemdc, membitmap, 0, height, databuf, bmi, DIB_RGB_COLORS);
 
1551
 
 
1552
        // Cleanup
 
1553
        free(bmi);
 
1554
        DeleteObject(membitmap);
 
1555
 
 
1556
        return (lines != 0);
 
1557
}
 
1558
 
 
1559
// Return the current mouse pointer position
 
1560
RECT
 
1561
vncDesktop::MouseRect()
 
1562
{
 
1563
        return m_cursorpos;
 
1564
}
 
1565
 
 
1566
void vncDesktop::SetCursor(HCURSOR cursor)
 
1567
{
 
1568
        if (cursor == NULL)
 
1569
                m_hcursor = m_hdefcursor;
 
1570
        else
 
1571
                m_hcursor = cursor;
 
1572
}
 
1573
 
 
1574
//
 
1575
// DEBUG: Some visualization for LF->CRLF conversion code.
 
1576
//
 
1577
/*
 
1578
static void ShowClipText(char *caption, char *text)
 
1579
{
 
1580
        int len = strlen(text);
 
1581
        char *out_text = new char[len * 4 + 8];
 
1582
        int pos = 0;
 
1583
 
 
1584
        out_text[pos++] = '"';
 
1585
        for (int i = 0; i < len; i++) {
 
1586
                if (text[i] == '\r') {
 
1587
                        strcpy(&out_text[pos], "\\r");
 
1588
                        pos += 2;
 
1589
                } else if (text[i] == '\n') {
 
1590
                        strcpy(&out_text[pos], "\\n");
 
1591
                        pos += 2;
 
1592
                } else if (text[i] < ' ') {
 
1593
                        strcpy(&out_text[pos], "\\?");
 
1594
                        pos += 2;
 
1595
                } else {
 
1596
                        out_text[pos++] = text[i];
 
1597
                }
 
1598
        }
 
1599
        out_text[pos++] = '"';
 
1600
        out_text[pos++] = '\0';
 
1601
 
 
1602
        MessageBox(NULL, out_text, caption, MB_OK);
 
1603
 
 
1604
        delete[] out_text;
 
1605
}
 
1606
*/
 
1607
 
 
1608
//
 
1609
// Convert text from Unix (LF only) format to CR+LF.
 
1610
// NOTE: The size of dst[] buffer must be at least (strlen(src) * 2 + 1).
 
1611
//
 
1612
 
 
1613
void
 
1614
vncDesktop::ConvertClipText(char *dst, const char *src)
 
1615
{
 
1616
        const char *ptr0 = src;
 
1617
        const char *ptr1;
 
1618
        int dst_pos = 0;
 
1619
 
 
1620
        while ((ptr1 = strchr(ptr0, '\n')) != NULL) {
 
1621
                // Copy the string before the LF
 
1622
                if (ptr1 != ptr0) {
 
1623
                        memcpy(&dst[dst_pos], ptr0, ptr1 - ptr0);
 
1624
                        dst_pos += ptr1 - ptr0;
 
1625
                }
 
1626
                // Don't insert CR if there is one already
 
1627
                if (ptr1 == ptr0 || *(ptr1 - 1) != '\r') {
 
1628
                        dst[dst_pos++] = '\r';
 
1629
                }
 
1630
                // Append LF
 
1631
                dst[dst_pos++] = '\n';
 
1632
                // Next position in the source text
 
1633
                ptr0 = ptr1 + 1;
 
1634
        }
 
1635
        // Copy the last string with no LF, but with '\0'
 
1636
        memcpy(&dst[dst_pos], ptr0, &src[strlen(src)] - ptr0 + 1);
 
1637
}
 
1638
 
 
1639
//
 
1640
// Manipulation of the clipboard
 
1641
//
 
1642
 
 
1643
void
 
1644
vncDesktop::SetClipText(LPSTR text)
 
1645
{
 
1646
        // Open the system clipboard
 
1647
        if (OpenClipboard(m_hwnd))
 
1648
        {
 
1649
                // Empty it
 
1650
                if (EmptyClipboard())
 
1651
                {
 
1652
                        HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
 
1653
                                                                          strlen(text) * 2 + 1);
 
1654
 
 
1655
                        if (hMem != NULL)
 
1656
                        {
 
1657
                                LPSTR pMem = (char*)GlobalLock(hMem);
 
1658
 
 
1659
                                // Get the data (with line endings converted to CR+LF)
 
1660
                                ConvertClipText(pMem, text);
 
1661
 
 
1662
                                // Tell the clipboard
 
1663
                                GlobalUnlock(hMem);
 
1664
                                SetClipboardData(CF_TEXT, hMem);
 
1665
                        }
 
1666
                }
 
1667
        }
 
1668
 
 
1669
        // Now close it
 
1670
        CloseClipboard();
 
1671
}
 
1672
 
 
1673
// INTERNAL METHODS
 
1674
 
 
1675
inline void
 
1676
vncDesktop::MaskToMaxAndShift(DWORD mask, CARD16 &max, CARD8 &shift)
 
1677
{
 
1678
        for (shift = 0; (mask & 1) == 0; shift++)
 
1679
                mask >>= 1;
 
1680
        max = (CARD16) mask;
 
1681
}
 
1682
 
 
1683
// Copy data from the memory bitmap into a buffer
 
1684
void vncDesktop::CopyToBuffer(RECT rect, BYTE *destbuff)
 
1685
{
 
1686
        // Are we being asked to blit from the DIBsection to itself?
 
1687
        if (destbuff == m_DIBbits)
 
1688
        {
 
1689
                // Yes.  Ignore the request!
 
1690
                return;
 
1691
        }
 
1692
 
 
1693
        // Protect the memory bitmap
 
1694
        omni_mutex_lock l(m_bitbltlock);
 
1695
 
 
1696
        const int crect_re_vd_left = rect.left - m_bmrect.left;
 
1697
        const int crect_re_vd_top = rect.top - m_bmrect.top;
 
1698
        _ASSERTE(crect_re_vd_left >= 0);
 
1699
        _ASSERTE(crect_re_vd_top >= 0);
 
1700
 
 
1701
        // Calculate the scanline-ordered y position to copy from
 
1702
// NB: m_membitmap is bottom2top
 
1703
        const int y_inv_re_vd = m_bmrect.bottom - m_bmrect.top - rect.bottom;
 
1704
        _ASSERTE(y_inv_re_vd >= 0);
 
1705
 
 
1706
        // Calculate where in the output buffer to put the data
 
1707
        BYTE * destbuffpos = destbuff + (m_bytesPerRow * crect_re_vd_top);
 
1708
 
 
1709
        // Set the number of bytes for GetDIBits to actually write
 
1710
        // NOTE : GetDIBits pads the destination buffer if biSizeImage < no. of bytes required
 
1711
        m_bminfo.bmi.bmiHeader.biSizeImage = (rect.bottom-rect.top) * m_bytesPerRow;
 
1712
 
 
1713
        // Get the actual bits from the bitmap into the bit buffer
 
1714
        // If fast (DIBsection) blits are disabled then use the old GetDIBits technique
 
1715
        if (m_DIBbits == NULL)
 
1716
        {
 
1717
                if (GetDIBits(
 
1718
                        m_hmemdc,
 
1719
                        m_membitmap,
 
1720
                        y_inv_re_vd,
 
1721
                        rect.bottom - rect.top,
 
1722
                        destbuffpos,
 
1723
                        &m_bminfo.bmi,
 
1724
                        DIB_RGB_COLORS) == 0)
 
1725
                {
 
1726
#ifdef _MSC_VER
 
1727
                        _RPT1(_CRT_WARN, "vncDesktop : [1] GetDIBits failed! %d\n", GetLastError());
 
1728
                        _RPT3(_CRT_WARN, "vncDesktop : thread = %d, DC = %d, bitmap = %d\n", omni_thread::self(), m_hmemdc, m_membitmap);
 
1729
                        _RPT2(_CRT_WARN, "vncDesktop : y = %d, height = %d\n", y_inv_re_vd, (rect.bottom-rect.top));
 
1730
#endif
 
1731
                }
 
1732
        }
 
1733
        else
 
1734
        {
 
1735
                // Fast blits are enabled.  [I have a sneaking suspicion this will never get used, unless
 
1736
                // something weird goes wrong in the code.  It's here to keep the function general, though!]
 
1737
 
 
1738
                const int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
1739
                BYTE *srcbuffpos = (BYTE*)m_DIBbits;
 
1740
 
 
1741
                srcbuffpos += (m_bytesPerRow * crect_re_vd_top) + (bytesPerPixel * crect_re_vd_left);
 
1742
                destbuffpos += bytesPerPixel * crect_re_vd_left;
 
1743
 
 
1744
                const int widthBytes = (rect.right - rect.left) * bytesPerPixel;
 
1745
 
 
1746
                for (int y = rect.top; y < rect.bottom; y++)
 
1747
                {
 
1748
                        memcpy(destbuffpos, srcbuffpos, widthBytes);
 
1749
                        srcbuffpos += m_bytesPerRow;
 
1750
                        destbuffpos += m_bytesPerRow;
 
1751
                }
 
1752
        }
 
1753
}
 
1754
 
 
1755
void vncDesktop::CopyToBuffer(RECT rect, BYTE *destbuff, const BYTE *srcbuffpos)
 
1756
{
 
1757
        const int crect_re_vd_left = rect.left - m_bmrect.left;
 
1758
        const int crect_re_vd_top = rect.top - m_bmrect.top;
 
1759
        _ASSERTE(crect_re_vd_left >= 0);
 
1760
        _ASSERTE(crect_re_vd_top >= 0);
 
1761
 
 
1762
        const int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
1763
 
 
1764
        const int bmoffset = (m_bytesPerRow * crect_re_vd_top) + (bytesPerPixel * crect_re_vd_left);
 
1765
        BYTE *destbuffpos = destbuff + bmoffset;
 
1766
        srcbuffpos += bmoffset;
 
1767
 
 
1768
        const int widthBytes = (rect.right - rect.left) * bytesPerPixel;
 
1769
 
 
1770
        for (int y = rect.top; y < rect.bottom; y++)
 
1771
        {
 
1772
                memcpy(destbuffpos, srcbuffpos, widthBytes);
 
1773
                srcbuffpos += m_bytesPerRow;
 
1774
                destbuffpos += m_bytesPerRow;
 
1775
        }
 
1776
}
 
1777
 
 
1778
// Callback routine used internally to catch window movement...
 
1779
BOOL CALLBACK
 
1780
EnumWindowsFnCopyRect(HWND hwnd, LPARAM arg)
 
1781
{
 
1782
 
 
1783
        //For excluding the popup windows
 
1784
        if ((GetWindowLong( hwnd, GWL_STYLE) & WS_POPUP) ==0)
 
1785
        {
 
1786
        
 
1787
                HANDLE prop = GetProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
 
1788
                if (prop != NULL) {
 
1789
                        
 
1790
                        if (IsWindowVisible(hwnd)) {
 
1791
                                
 
1792
                                RECT dest;
 
1793
                                POINT source;
 
1794
 
 
1795
                                // Get the window rectangle
 
1796
                                if (GetWindowRect(hwnd, &dest)) {
 
1797
                                        // Old position
 
1798
                                        source.x = (SHORT) LOWORD(prop);
 
1799
                                        source.y = (SHORT) HIWORD(prop);
 
1800
 
 
1801
                                        // Got the destination position.  Now send to clients!
 
1802
                                        if ((source.x != dest.left) || (source.y != dest.top)) {
 
1803
                                                // Update the property entry
 
1804
                                                SHORT x = (SHORT) dest.left;
 
1805
                                                SHORT y = (SHORT) dest.top;
 
1806
                                                SetProp(hwnd,
 
1807
                                                        (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0),
 
1808
                                                        (HANDLE) MAKELONG(x, y));
 
1809
 
 
1810
                                                // Store of the copyrect 
 
1811
                                                ((vncDesktop*)arg)->CopyRect(dest, source);
 
1812
                                                
 
1813
                                        }
 
1814
                                } else {
 
1815
                                        RemoveProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
 
1816
                                }
 
1817
                        } else {
 
1818
                                RemoveProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
 
1819
                        }
 
1820
                } else {
 
1821
                        // If the window has become visible then save its position!
 
1822
                        if (IsWindowVisible(hwnd)) {
 
1823
                                RECT dest;
 
1824
 
 
1825
                                if (GetWindowRect(hwnd, &dest)) {
 
1826
                                        SHORT x = (SHORT) dest.left;
 
1827
                                        SHORT y = (SHORT) dest.top;
 
1828
                                        SetProp(hwnd,
 
1829
                                                (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0),
 
1830
                                                (HANDLE) MAKELONG(x, y));
 
1831
                                }
 
1832
                        }
 
1833
                }
 
1834
        }
 
1835
        return TRUE;
 
1836
}
 
1837
 
 
1838
 
 
1839
void
 
1840
vncDesktop::SetLocalInputDisableHook(BOOL enable)
 
1841
{
 
1842
        SetKeyboardFilterHook(enable);
 
1843
        SetMouseFilterHook(enable);
 
1844
}
 
1845
 
 
1846
void
 
1847
vncDesktop::SetLocalInputPriorityHook(BOOL enable)
 
1848
{
 
1849
        if (vncService::IsWin95()) {
 
1850
                SetKeyboardPriorityHook(m_hwnd,enable,RFB_LOCAL_KEYBOARD);
 
1851
                SetMousePriorityHook(m_hwnd,enable,RFB_LOCAL_MOUSE);
 
1852
        } else {
 
1853
                SetKeyboardPriorityLLHook(m_hwnd,enable,RFB_LOCAL_KEYBOARD);
 
1854
                SetMousePriorityLLHook(m_hwnd,enable,RFB_LOCAL_MOUSE);
 
1855
        }
 
1856
 
 
1857
        if (!enable)
 
1858
// FIXME: incremental semantics broken here;
 
1859
// that's why we're compelled to consume extra unlocks
 
1860
                m_server->BlockRemoteInput(false);
 
1861
}
 
1862
 
 
1863
// Routine to find out which windows have moved
 
1864
void
 
1865
vncDesktop::CalcCopyRects()
 
1866
{
 
1867
        // Enumerate all the desktop windows for movement
 
1868
        EnumWindows((WNDENUMPROC)EnumWindowsFnCopyRect, (LPARAM) this);
 
1869
}
 
1870
 
 
1871
 
 
1872
// Window procedure for the Desktop window
 
1873
LRESULT CALLBACK
 
1874
DesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
 
1875
{
 
1876
        vncDesktop *_this = (vncDesktop*)GetWindowLong(hwnd, GWL_USERDATA);
 
1877
 
 
1878
        switch (iMsg)
 
1879
        {
 
1880
 
 
1881
                // GENERAL
 
1882
 
 
1883
        case WM_DISPLAYCHANGE:
 
1884
                // The display resolution is changing
 
1885
 
 
1886
                // We must kick off any clients since their screen size will be wrong
 
1887
                _this->m_displaychanged = TRUE;
 
1888
                return 0;
 
1889
 
 
1890
        case WM_SYSCOLORCHANGE:
 
1891
        case WM_PALETTECHANGED:
 
1892
                // The palette colours have changed, so tell the server
 
1893
 
 
1894
                // Get the system palette
 
1895
                if (!_this->SetPalette())
 
1896
                        PostQuitMessage(0);
 
1897
                // Update any palette-based clients, too
 
1898
                _this->m_server->UpdatePalette();
 
1899
                return 0;
 
1900
 
 
1901
        case WM_TIMER:
 
1902
                switch (wParam) {
 
1903
                case vncDesktop::TIMER_POLL:
 
1904
                        _this->SetPollingFlag(true);
 
1905
                        break;
 
1906
                case vncDesktop::TIMER_BLANK_SCREEN:
 
1907
                        if (_this->m_server->GetBlankScreen())
 
1908
                                _this->BlankScreen(TRUE);
 
1909
                        break;
 
1910
                case vncDesktop::TIMER_RESTORE_SCREEN:
 
1911
                        _this->BlankScreen(FALSE);
 
1912
                        break;
 
1913
                }
 
1914
                return 0;
 
1915
 
 
1916
                // CLIPBOARD MESSAGES
 
1917
 
 
1918
        case WM_CHANGECBCHAIN:
 
1919
                // The clipboard chain has changed - check our nextviewer handle
 
1920
                if ((HWND)wParam == _this->m_hnextviewer)
 
1921
                        _this->m_hnextviewer = (HWND)lParam;
 
1922
                else
 
1923
                        if (_this->m_hnextviewer != NULL)
 
1924
                                SendMessage(_this->m_hnextviewer,
 
1925
                                                        WM_CHANGECBCHAIN,
 
1926
                                                        wParam, lParam);
 
1927
 
 
1928
                return 0;
 
1929
 
 
1930
        case WM_DRAWCLIPBOARD:
 
1931
                // The clipboard contents have changed
 
1932
                if((GetClipboardOwner() != _this->Window()) &&
 
1933
                    _this->m_initialClipBoardSeen &&
 
1934
                        _this->m_clipboard_active)
 
1935
                {
 
1936
                        LPSTR cliptext = NULL;
 
1937
 
 
1938
                        // Open the clipboard
 
1939
                        if (OpenClipboard(_this->Window()))
 
1940
                        {
 
1941
                                // Get the clipboard data
 
1942
                                HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
 
1943
                                if (cliphandle != NULL)
 
1944
                                {
 
1945
                                        LPSTR clipdata = (LPSTR) GlobalLock(cliphandle);
 
1946
 
 
1947
                                        // Copy it into a new buffer
 
1948
                                        if (clipdata == NULL)
 
1949
                                                cliptext = NULL;
 
1950
                                        else
 
1951
                                                cliptext = strdup(clipdata);
 
1952
 
 
1953
                                        // Release the buffer and close the clipboard
 
1954
                                        GlobalUnlock(cliphandle);
 
1955
                                }
 
1956
 
 
1957
                                CloseClipboard();
 
1958
                        }
 
1959
 
 
1960
                        if (cliptext != NULL)
 
1961
                        {
 
1962
                                int cliplen = strlen(cliptext);
 
1963
                                LPSTR unixtext = (char *)malloc(cliplen+1);
 
1964
 
 
1965
                                // Replace CR-LF with LF - never send CR-LF on the wire,
 
1966
                                // since Unix won't like it
 
1967
                                int unixpos=0;
 
1968
                                for (int x=0; x<cliplen; x++)
 
1969
                                {
 
1970
                                        if (cliptext[x] != '\x0d')
 
1971
                                        {
 
1972
                                                unixtext[unixpos] = cliptext[x];
 
1973
                                                unixpos++;
 
1974
                                        }
 
1975
                                }
 
1976
                                unixtext[unixpos] = 0;
 
1977
 
 
1978
                                // Free the clip text
 
1979
                                free(cliptext);
 
1980
                                cliptext = NULL;
 
1981
 
 
1982
                                // Now send the unix text to the server
 
1983
                                _this->m_server->UpdateClipText(unixtext);
 
1984
 
 
1985
                                free(unixtext);
 
1986
                        }
 
1987
                }
 
1988
 
 
1989
                _this->m_initialClipBoardSeen = TRUE;
 
1990
 
 
1991
                if (_this->m_hnextviewer != NULL)
 
1992
                {
 
1993
                        // Pass the message to the next window in clipboard viewer chain.  
 
1994
                        return SendMessage(_this->m_hnextviewer, WM_DRAWCLIPBOARD, 0,0); 
 
1995
                }
 
1996
 
 
1997
                return 0;
 
1998
 
 
1999
        default:
 
2000
                return DefWindowProc(hwnd, iMsg, wParam, lParam);
 
2001
        }
 
2002
}
 
2003
 
 
2004
BOOL vncDesktop::CheckUpdates()
 
2005
{
 
2006
#ifndef _DEBUG
 
2007
        try
 
2008
        {
 
2009
#endif
 
2010
                // Re-install polling timer if necessary
 
2011
                if (m_server->PollingCycleChanged())
 
2012
                {
 
2013
                        SetPollingTimer();
 
2014
                        m_server->PollingCycleChanged(false);
 
2015
                }
 
2016
 
 
2017
                // Update the state of blank screen timer
 
2018
                UpdateBlankScreenTimer();
 
2019
 
 
2020
                // Has the display resolution or desktop changed?
 
2021
                if (m_displaychanged || !vncService::InputDesktopSelected() /*|| !inConsoleSession()*/)
 
2022
                {
 
2023
                        vnclog.Print(LL_STATE, VNCLOG("display resolution or desktop changed.\n"));
 
2024
 
 
2025
                        rfbServerInitMsg oldscrinfo = m_scrinfo;
 
2026
                        m_displaychanged = FALSE;
 
2027
 
 
2028
                        // Attempt to close the old hooks
 
2029
                        if (!Shutdown())
 
2030
                        {
 
2031
                                vnclog.Print(LL_INTERR, VNCLOG("failed to close desktop server.\n"));
 
2032
                                m_server->KillAuthClients();
 
2033
                                return FALSE;
 
2034
                        }
 
2035
 
 
2036
                        // Now attempt to re-install them!
 
2037
                        ChangeResNow();
 
2038
 
 
2039
                        if (!Startup())
 
2040
                        {
 
2041
                                vnclog.Print(LL_INTERR, VNCLOG("failed to re-start desktop server.\n"));
 
2042
                                m_server->KillAuthClients();
 
2043
                                return FALSE;
 
2044
                        }
 
2045
 
 
2046
                        // Check if the screen info has changed
 
2047
                        vnclog.Print(LL_INTINFO,
 
2048
                                                VNCLOG("SCR: old screen format %dx%dx%d\n"),
 
2049
                                                oldscrinfo.framebufferWidth,
 
2050
                                                oldscrinfo.framebufferHeight,
 
2051
                                                oldscrinfo.format.bitsPerPixel);
 
2052
                        vnclog.Print(LL_INTINFO,
 
2053
                                                VNCLOG("SCR: new screen format %dx%dx%d\n"),
 
2054
                                                m_scrinfo.framebufferWidth,
 
2055
                                                m_scrinfo.framebufferHeight,
 
2056
                                                m_scrinfo.format.bitsPerPixel);
 
2057
                        if (memcmp(&m_scrinfo, &oldscrinfo, sizeof(oldscrinfo)) != 0)
 
2058
                        {
 
2059
                                vnclog.Print(LL_INTINFO, VNCLOG("screen format has changed.\n"));
 
2060
                        }
 
2061
 
 
2062
                        // Call this regardless of screen format change
 
2063
                        m_server->UpdateLocalFormat();
 
2064
 
 
2065
                        // Add a full screen update to all the clients
 
2066
                        m_changed_rgn.AddRect(m_bmrect);
 
2067
                        m_server->UpdatePalette();
 
2068
                }
 
2069
 
 
2070
                // TRIGGER THE UPDATE
 
2071
 
 
2072
                RECT rect = m_server->GetSharedRect();
 
2073
                RECT new_rect = GetSourceRect();
 
2074
                IntersectRect(&new_rect, &new_rect, &m_bmrect);
 
2075
 
 
2076
                // Update screen size if required
 
2077
                if (!EqualRect(&new_rect, &rect))
 
2078
                {
 
2079
                        m_server->SetSharedRect(new_rect);
 
2080
                        bool sendnewfb = false;
 
2081
 
 
2082
                        if (rect.right - rect.left != new_rect.right - new_rect.left ||
 
2083
                                rect.bottom - rect.top != new_rect.bottom - new_rect.top)
 
2084
                                sendnewfb = true;
 
2085
 
 
2086
                        // FIXME: We should not send NewFBSize if a client
 
2087
                        //        did not send framebuffer update request.
 
2088
                        m_server->SetNewFBSize(sendnewfb);
 
2089
 
 
2090
                        m_changed_rgn.Clear();
 
2091
 
 
2092
                        if (sendnewfb && m_server->WindowShared())
 
2093
                        {
 
2094
                                if (new_rect.right - new_rect.left == 0 &&
 
2095
                                        new_rect.bottom - new_rect.top == 0)
 
2096
                                {
 
2097
// window is minimized
 
2098
                                        return TRUE;
 
2099
                                }
 
2100
                                else
 
2101
                                {
 
2102
// window is restored
 
2103
// window is resized
 
2104
                                        m_changed_rgn.AddRect(new_rect);
 
2105
                                }
 
2106
                        }
 
2107
                        else
 
2108
                        {
 
2109
                                return TRUE;
 
2110
                        }
 
2111
                }
 
2112
 
 
2113
                // If we have clients full region requests
 
2114
                if (m_server->FullRgnRequested())
 
2115
                {
 
2116
                        // Capture screen to main buffer
 
2117
                        CaptureScreen(rect, m_mainbuff);
 
2118
                        // If we have a video driver - reset counter
 
2119
                        if ( m_videodriver != NULL && m_videodriver->IsActive())
 
2120
                        {
 
2121
                                m_videodriver->ResetCounter();
 
2122
                        }
 
2123
                }
 
2124
 
 
2125
// DEBUG: Continue auditing the code from this point.
 
2126
 
 
2127
                // If we have incremental update requests
 
2128
                if (m_server->IncrRgnRequested())
 
2129
                {
 
2130
                        vncRegion rgn;
 
2131
 
 
2132
                        // Use either a mirror video driver, or perform polling
 
2133
                        if (m_videodriver != NULL && m_videodriver->IsActive())
 
2134
                        {
 
2135
                                // FIXME: If there were no incremental update requests
 
2136
                                //        for some time, we will loose updates.
 
2137
// IMPORTANT: Mirage outputs the regions re (0, 0)
 
2138
// so we have to offset them re virtual display
 
2139
 
 
2140
// TODOTODO
 
2141
                                        BOOL bCursorShape = FALSE;
 
2142
 
 
2143
                                        m_videodriver->HandleDriverChanges(
 
2144
                                                this,
 
2145
                                                m_changed_rgn,
 
2146
                                                m_bmrect.left,
 
2147
                                                m_bmrect.top,
 
2148
                                                bCursorShape);
 
2149
                        }
 
2150
                        else
 
2151
                        {
 
2152
                                if (GetPollingFlag())
 
2153
                                {
 
2154
                                        SetPollingFlag(false);
 
2155
                                        PerformPolling();
 
2156
                                }
 
2157
                        }
 
2158
 
 
2159
                        // Check for moved windows
 
2160
// PrimaryDisplayOnlyShared: check if any problems when
 
2161
// dragging from another display
 
2162
                        if ((m_server->FullScreen() || m_server->PrimaryDisplayOnlyShared()) &&
 
2163
                                !(m_videodriver && m_videodriver->IsHandlingScreen2ScreenBlt()))
 
2164
                        {
 
2165
                                CalcCopyRects();
 
2166
                        }
 
2167
 
 
2168
                        if (m_copyrect_set)
 
2169
                        {
 
2170
                                // Send copyrect to all clients
 
2171
                                m_server->CopyRect(m_copyrect_rect, m_copyrect_src);
 
2172
                                m_copyrect_set = false;
 
2173
 
 
2174
// IMPORTANT: this order: CopyRectToBuffer, CaptureScreen, GetChangedRegion
 
2175
                                // Copy old window rect to back buffer
 
2176
                                CopyRectToBuffer(m_copyrect_rect, m_copyrect_src);
 
2177
 
 
2178
                                // Copy new window rect to main buffer
 
2179
                                CaptureScreen(m_copyrect_rect, m_mainbuff);
 
2180
 
 
2181
                                // Get changed pixels to rg
 
2182
                                GetChangedRegion(rgn, m_copyrect_rect);
 
2183
 
 
2184
                                RECT rect;
 
2185
                                rect.left= m_copyrect_src.x;
 
2186
                                rect.top = m_copyrect_src.y;
 
2187
                                rect.right = rect.left + (m_copyrect_rect.right - m_copyrect_rect.left);
 
2188
                                rect.bottom = rect.top + (m_copyrect_rect.bottom - m_copyrect_rect.top);
 
2189
                                // Refresh old window rect
 
2190
                                m_changed_rgn.AddRect(rect);
 
2191
                                // Don't refresh new window rect
 
2192
                                m_changed_rgn.SubtractRect(m_copyrect_rect);
 
2193
                        } 
 
2194
 
 
2195
                        // Get only desktop area
 
2196
                        vncRegion temprgn;
 
2197
                        temprgn.Clear();
 
2198
                        temprgn.AddRect(rect);
 
2199
                        m_changed_rgn.Intersect(temprgn);
 
2200
 
 
2201
                        // Get list of rectangles for checking
 
2202
                        rectlist rectsToScan;
 
2203
                        m_changed_rgn.Rectangles(rectsToScan);
 
2204
 
 
2205
                        // Capture and check them
 
2206
                        CheckRects(rgn, rectsToScan);
 
2207
 
 
2208
                        // Update the mouse
 
2209
                        m_server->UpdateMouse();
 
2210
 
 
2211
                        // Send changed region data to all clients
 
2212
                        m_server->UpdateRegion(rgn);
 
2213
 
 
2214
                        // Clear changed region
 
2215
                        m_changed_rgn.Clear();
 
2216
                }
 
2217
 
 
2218
                // Trigger an update to be sent
 
2219
                if (m_server->FullRgnRequested() || m_server->IncrRgnRequested())
 
2220
                {
 
2221
                        m_server->TriggerUpdate();
 
2222
                }
 
2223
 
 
2224
#ifndef _DEBUG
 
2225
        }
 
2226
        catch (...)
 
2227
        {
 
2228
                vnclog.Print(LL_INTERR, VNCLOG("vncDesktop::CheckUpdates caught an exception.\n"));
 
2229
                m_server->KillAuthClients();
 
2230
                return FALSE;
 
2231
        }
 
2232
#endif
 
2233
 
 
2234
        return TRUE;
 
2235
}
 
2236
 
 
2237
void
 
2238
vncDesktop::SetPollingTimer()
 
2239
{
 
2240
        const UINT driverCycle = 30;
 
2241
        const UINT minPollingCycle = 5;
 
2242
 
 
2243
        UINT msec;
 
2244
        if (m_videodriver != NULL) {
 
2245
                msec = driverCycle;
 
2246
        } else {
 
2247
                msec = m_server->GetPollingCycle() / 16;
 
2248
                if (msec < minPollingCycle) {
 
2249
                        msec = minPollingCycle;
 
2250
                }
 
2251
        }
 
2252
        m_timer_polling = SetTimer(Window(), TIMER_POLL, msec, NULL);
 
2253
}
 
2254
 
 
2255
inline void vncDesktop::CheckRects(vncRegion &rgn, rectlist &rects)
 
2256
{
 
2257
#ifndef _DEBUG
 
2258
        try
 
2259
        {
 
2260
#endif
 
2261
                rectlist::iterator i;
 
2262
 
 
2263
                for (i = rects.begin(); i != rects.end(); i++)
 
2264
                {
 
2265
                        // Copy data to the main buffer
 
2266
                        // FIXME: Maybe call CaptureScreen() just once?
 
2267
                        //        Check what would be more efficient.
 
2268
                        CaptureScreen(*i, m_mainbuff);
 
2269
 
 
2270
// Check for changes in the rectangle
 
2271
                        GetChangedRegion(rgn, *i);
 
2272
                }
 
2273
#ifndef _DEBUG
 
2274
        }
 
2275
        catch (...)
 
2276
        {
 
2277
                vnclog.Print(LL_INTERR, VNCLOG("vncDesktop::CheckRects caught an exception.\n"));
 
2278
                throw;
 
2279
        }
 
2280
#endif
 
2281
}
 
2282
 
 
2283
#ifdef _MSC_VER
 
2284
// This notably improves performance when using Visual C++ 6.0 compiler
 
2285
#pragma function(memcpy, memcmp)
 
2286
#endif
 
2287
 
 
2288
static const int BLOCK_SIZE = 32;
 
2289
 
 
2290
// created for troubleshoot purposes;
 
2291
// when GetChangedRegion_Normal et al are suspected for bugs/need changes.
 
2292
// the code below is as simple and clear as possible
 
2293
void vncDesktop::GetChangedRegion_Dummy(vncRegion &rgn, const RECT &rect)
 
2294
{
 
2295
        rgn.AddRect(rect);
 
2296
 
 
2297
        // Copy the changes to the back buffer
 
2298
        const int c2rect_re_vd_top = rect.top - m_bmrect.top;
 
2299
        const int c3rect_re_vd_left = rect.left - m_bmrect.left;
 
2300
        _ASSERTE(c2rect_re_vd_top >= 0);
 
2301
        _ASSERTE(c3rect_re_vd_left >= 0);
 
2302
 
 
2303
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
2304
        const int offset = c2rect_re_vd_top * m_bytesPerRow + c3rect_re_vd_left * bytesPerPixel;
 
2305
 
 
2306
        unsigned char *o_ptr = m_backbuff + offset;
 
2307
        unsigned char *n_ptr = m_mainbuff + offset;
 
2308
        const int bytes_in_row = (rect.right - rect.left) * bytesPerPixel;
 
2309
        for (int y = rect.top; y < rect.bottom; y++)
 
2310
        {
 
2311
                memcpy(o_ptr, n_ptr, bytes_in_row);
 
2312
                n_ptr += m_bytesPerRow;
 
2313
                o_ptr += m_bytesPerRow;
 
2314
        }
 
2315
}
 
2316
 
 
2317
void vncDesktop::GetChangedRegion_Normal(vncRegion &rgn, const RECT &rect)
 
2318
{
 
2319
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
2320
        const int bytes_per_scanline = (rect.right - rect.left) * bytesPerPixel;
 
2321
 
 
2322
        const int crect_re_vd_left = rect.left - m_bmrect.left;
 
2323
        const int crect_re_vd_top = rect.top - m_bmrect.top;
 
2324
        _ASSERTE(crect_re_vd_left >= 0);
 
2325
        _ASSERTE(crect_re_vd_top >= 0);
 
2326
 
 
2327
        const int offset = crect_re_vd_top * m_bytesPerRow + crect_re_vd_left * bytesPerPixel;
 
2328
        unsigned char *o_ptr = m_backbuff + offset;
 
2329
        unsigned char *n_ptr = m_mainbuff + offset;
 
2330
 
 
2331
        RECT new_rect = rect;
 
2332
 
 
2333
        // Fast processing for small rectangles
 
2334
        if (rect.right - rect.left <= BLOCK_SIZE &&
 
2335
                rect.bottom - rect.top <= BLOCK_SIZE)
 
2336
        {
 
2337
                for (int y = rect.top; y < rect.bottom; y++)
 
2338
                {
 
2339
                        if (memcmp(o_ptr, n_ptr, bytes_per_scanline) != 0)
 
2340
                        {
 
2341
                                new_rect.top = y;
 
2342
                                UpdateChangedSubRect(rgn, new_rect);
 
2343
                                break;
 
2344
                        }
 
2345
                        o_ptr += m_bytesPerRow;
 
2346
                        n_ptr += m_bytesPerRow;
 
2347
                }
 
2348
                return;
 
2349
        }
 
2350
 
 
2351
// Process bigger rectangles
 
2352
        BOOL bTop4Move = TRUE;
 
2353
        for (int y = rect.top; y < rect.bottom; y++)
 
2354
        {
 
2355
                if (memcmp(o_ptr, n_ptr, bytes_per_scanline) != 0)
 
2356
                {
 
2357
                        if (bTop4Move)
 
2358
                        {
 
2359
                                new_rect.top = y;
 
2360
                                bTop4Move = FALSE;
 
2361
                        }
 
2362
                        // Skip a number of lines after a non-matched one
 
2363
                        int n = BLOCK_SIZE / 2 - 1;
 
2364
                        y += n;
 
2365
                        o_ptr += n * m_bytesPerRow;
 
2366
                        n_ptr += n * m_bytesPerRow;
 
2367
                }
 
2368
                else
 
2369
                {
 
2370
                        if (!bTop4Move)
 
2371
                        {
 
2372
                                new_rect.bottom = y;
 
2373
                                UpdateChangedRect(rgn, new_rect);
 
2374
                                bTop4Move = TRUE;
 
2375
                        }
 
2376
                }
 
2377
                o_ptr += m_bytesPerRow;
 
2378
                n_ptr += m_bytesPerRow;
 
2379
        }
 
2380
        if (!bTop4Move)
 
2381
        {
 
2382
                new_rect.bottom = rect.bottom;
 
2383
                UpdateChangedRect(rgn, new_rect);
 
2384
        }
 
2385
}
 
2386
 
 
2387
void vncDesktop::UpdateChangedRect(vncRegion &rgn, const RECT &rect)
 
2388
{
 
2389
        // Pass small rectangles directly to UpdateChangedSubRect
 
2390
        if (rect.right - rect.left <= BLOCK_SIZE &&
 
2391
                rect.bottom - rect.top <= BLOCK_SIZE)
 
2392
        {
 
2393
                UpdateChangedSubRect(rgn, rect);
 
2394
                return;
 
2395
        }
 
2396
 
 
2397
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
2398
 
 
2399
        RECT new_rect;
 
2400
        int x, y, ay;
 
2401
 
 
2402
        const int crect_re_vd_left = rect.left - m_bmrect.left;
 
2403
        const int crect_re_vd_top = rect.top - m_bmrect.top;
 
2404
        _ASSERTE(crect_re_vd_left >= 0);
 
2405
        _ASSERTE(crect_re_vd_top >= 0);
 
2406
 
 
2407
        // Scan down the rectangle
 
2408
        const int offset = crect_re_vd_top * m_bytesPerRow + crect_re_vd_left * bytesPerPixel;
 
2409
        unsigned char *o_topleft_ptr = m_backbuff + offset;
 
2410
        unsigned char *n_topleft_ptr = m_mainbuff + offset;
 
2411
 
 
2412
        for (y = rect.top; y < rect.bottom; y += BLOCK_SIZE)
 
2413
        {
 
2414
                // Work out way down the bitmap
 
2415
                unsigned char *o_row_ptr = o_topleft_ptr;
 
2416
                unsigned char *n_row_ptr = n_topleft_ptr;
 
2417
 
 
2418
                const int blockbottom = Min(y + BLOCK_SIZE, rect.bottom);
 
2419
                new_rect.bottom = blockbottom;
 
2420
 
 
2421
                BOOL bLeft4Move = TRUE;
 
2422
 
 
2423
                for (x = rect.left; x < rect.right; x += BLOCK_SIZE)
 
2424
                {
 
2425
                        // Work our way across the row
 
2426
                        unsigned char *n_block_ptr = n_row_ptr;
 
2427
                        unsigned char *o_block_ptr = o_row_ptr;
 
2428
 
 
2429
                        const UINT blockright = Min(x + BLOCK_SIZE, rect.right);
 
2430
                        const UINT bytesPerBlockRow = (blockright-x) * bytesPerPixel;
 
2431
 
 
2432
                        // Scan this block
 
2433
                        for (ay = y; ay < blockbottom; ay++)
 
2434
                        {
 
2435
                                if (memcmp(n_block_ptr, o_block_ptr, bytesPerBlockRow) != 0)
 
2436
                                        break;
 
2437
                                n_block_ptr += m_bytesPerRow;
 
2438
                                o_block_ptr += m_bytesPerRow;
 
2439
                        }
 
2440
                        if (ay < blockbottom)
 
2441
                        {
 
2442
                                // There were changes, so this block will need to be updated
 
2443
                                if (bLeft4Move)
 
2444
                                {
 
2445
                                        new_rect.left = x;
 
2446
                                        bLeft4Move = FALSE;
 
2447
                                        new_rect.top = ay;
 
2448
                                }
 
2449
                                else if (ay < new_rect.top)
 
2450
                                {
 
2451
                                        new_rect.top = ay;
 
2452
                                }
 
2453
                        }
 
2454
                        else
 
2455
                        {
 
2456
                                // No changes in this block, process previous changed blocks if any
 
2457
                                if (!bLeft4Move)
 
2458
                                {
 
2459
                                        new_rect.right = x;
 
2460
                                        UpdateChangedSubRect(rgn, new_rect);
 
2461
                                        bLeft4Move = TRUE;
 
2462
                                }
 
2463
                        }
 
2464
 
 
2465
                        o_row_ptr += bytesPerBlockRow;
 
2466
                        n_row_ptr += bytesPerBlockRow;
 
2467
                }
 
2468
 
 
2469
                if (!bLeft4Move)
 
2470
                {
 
2471
                        new_rect.right = rect.right;
 
2472
                        UpdateChangedSubRect(rgn, new_rect);
 
2473
                }
 
2474
 
 
2475
                o_topleft_ptr += m_bytesPerRow * BLOCK_SIZE;
 
2476
                n_topleft_ptr += m_bytesPerRow * BLOCK_SIZE;
 
2477
        }
 
2478
}
 
2479
 
 
2480
void vncDesktop::UpdateChangedSubRect(vncRegion &rgn, const RECT &rect)
 
2481
{
 
2482
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
2483
        int bytes_in_row = (rect.right - rect.left) * bytesPerPixel;
 
2484
        int y, i;
 
2485
 
 
2486
        const int crect_re_vd_left = rect.left - m_bmrect.left;
 
2487
        const int crect_re_vd_bottom = rect.bottom - m_bmrect.top;
 
2488
        _ASSERTE(crect_re_vd_left >= 0);
 
2489
        _ASSERTE(crect_re_vd_bottom >= 0);
 
2490
 
 
2491
        // Exclude unchanged scan lines at the bottom
 
2492
        int offset = (crect_re_vd_bottom - 1) * m_bytesPerRow + crect_re_vd_left * bytesPerPixel;
 
2493
        unsigned char *o_ptr = m_backbuff + offset;
 
2494
        unsigned char *n_ptr = m_mainbuff + offset;
 
2495
        RECT final_rect = rect;
 
2496
        final_rect.bottom = rect.top + 1;
 
2497
        for (y = rect.bottom - 1; y > rect.top; y--)
 
2498
        {
 
2499
                if (memcmp(o_ptr, n_ptr, bytes_in_row) != 0)
 
2500
                {
 
2501
                        final_rect.bottom = y + 1;
 
2502
                        break;
 
2503
                }
 
2504
                n_ptr -= m_bytesPerRow;
 
2505
                o_ptr -= m_bytesPerRow;
 
2506
        }
 
2507
 
 
2508
        // Exclude unchanged pixels at left and right sides
 
2509
        const int c2rect_re_vd_left = final_rect.left - m_bmrect.left;
 
2510
        const int c2rect_re_vd_top = final_rect.top - m_bmrect.top;
 
2511
        _ASSERTE(c2rect_re_vd_left >= 0);
 
2512
        _ASSERTE(c2rect_re_vd_top >= 0);
 
2513
 
 
2514
        offset = c2rect_re_vd_top * m_bytesPerRow + c2rect_re_vd_left * bytesPerPixel;
 
2515
        o_ptr = m_backbuff + offset;
 
2516
        n_ptr = m_mainbuff + offset;
 
2517
        int left_delta = bytes_in_row - 1;
 
2518
        int right_delta = 0;
 
2519
        for (y = final_rect.top; y < final_rect.bottom; y++)
 
2520
        {
 
2521
                for (i = 0; i < bytes_in_row - 1; i++)
 
2522
                {
 
2523
                        if (n_ptr[i] != o_ptr[i])
 
2524
                        {
 
2525
                                if (i < left_delta)
 
2526
                                        left_delta = i;
 
2527
                                break;
 
2528
                        }
 
2529
                }
 
2530
                for (i = bytes_in_row - 1; i > 0; i--)
 
2531
                {
 
2532
                        if (n_ptr[i] != o_ptr[i])
 
2533
                        {
 
2534
                                if (i > right_delta)
 
2535
                                        right_delta = i;
 
2536
                                break;
 
2537
                        }
 
2538
                }
 
2539
                n_ptr += m_bytesPerRow;
 
2540
                o_ptr += m_bytesPerRow;
 
2541
        }
 
2542
        final_rect.right = final_rect.left + right_delta / bytesPerPixel + 1;
 
2543
        final_rect.left += left_delta / bytesPerPixel;
 
2544
 
 
2545
        // Update the rectangle
 
2546
        rgn.AddRect(final_rect);
 
2547
 
 
2548
        // Copy the changes to the back buffer
 
2549
        const int c3rect_re_vd_left = final_rect.left - m_bmrect.left;
 
2550
        _ASSERTE(c3rect_re_vd_left >= 0);
 
2551
 
 
2552
        offset = c2rect_re_vd_top * m_bytesPerRow + c3rect_re_vd_left * bytesPerPixel;
 
2553
 
 
2554
        o_ptr = m_backbuff + offset;
 
2555
        n_ptr = m_mainbuff + offset;
 
2556
        bytes_in_row = (final_rect.right - final_rect.left) * bytesPerPixel;
 
2557
        for (y = final_rect.top; y < final_rect.bottom; y++)
 
2558
        {
 
2559
                memcpy(o_ptr, n_ptr, bytes_in_row);
 
2560
                n_ptr += m_bytesPerRow;
 
2561
                o_ptr += m_bytesPerRow;
 
2562
        }
 
2563
}
 
2564
 
 
2565
 
 
2566
void vncDesktop::PerformPolling()
 
2567
{
 
2568
        if (m_server->PollFullScreen())
 
2569
        {
 
2570
                // Poll full screen
 
2571
                RECT full_rect = m_server->GetSharedRect();
 
2572
                PollArea(full_rect);
 
2573
        }
 
2574
        else
 
2575
        {
 
2576
                // Poll a window
 
2577
                if (m_server->PollForeground())
 
2578
                {
 
2579
                        // Get the window rectangle for the currently selected window
 
2580
                        HWND hwnd = GetForegroundWindow();
 
2581
                        if (hwnd != NULL)
 
2582
                                PollWindow(hwnd);
 
2583
                }
 
2584
                if (m_server->PollUnderCursor())
 
2585
                {
 
2586
                        // Find the mouse position
 
2587
                        POINT mousepos;
 
2588
                        if (GetCursorPos(&mousepos))
 
2589
                        {
 
2590
                                // Find the window under the mouse
 
2591
                                HWND hwnd = WindowFromPoint(mousepos);
 
2592
                                if (hwnd != NULL)
 
2593
                                        PollWindow(hwnd);
 
2594
                        }
 
2595
                }
 
2596
        }
 
2597
}
 
2598
 
 
2599
void
 
2600
vncDesktop::PollWindow(HWND hwnd)
 
2601
{
 
2602
        // Are we set to low-load polling?
 
2603
        if (m_server->PollOnEventOnly())
 
2604
        {
 
2605
                // Yes, so only poll if the remote user has done something
 
2606
                if (!m_server->RemoteEventReceived()) {
 
2607
                        return;
 
2608
                }
 
2609
        }
 
2610
 
 
2611
        // Does the client want us to poll only console windows?
 
2612
        if (m_server->PollConsoleOnly())
 
2613
        {
 
2614
                char classname[20];
 
2615
 
 
2616
                // Yes, so check that this is a console window...
 
2617
                if (GetClassName(hwnd, classname, sizeof(classname))) {
 
2618
                        if ((strcmp(classname, "tty") != 0) &&
 
2619
                                (strcmp(classname, "ConsoleWindowClass") != 0)) {
 
2620
                                return;
 
2621
                        }
 
2622
                }
 
2623
        }
 
2624
 
 
2625
        RECT full_rect = m_server->GetSharedRect();
 
2626
        RECT rect;
 
2627
 
 
2628
        // Get the rectangle
 
2629
        if (GetWindowRect(hwnd, &rect)) {
 
2630
                if (IntersectRect(&rect, &rect, &full_rect)) {
 
2631
                        PollArea(rect);
 
2632
                }
 
2633
        }
 
2634
}
 
2635
 
 
2636
//
 
2637
// Implementation of the polling algorithm.
 
2638
//
 
2639
 
 
2640
void vncDesktop::PollArea(const RECT &rect)
 
2641
{
 
2642
        const int scanLine = m_pollingOrder[m_pollingStep++ % 32];
 
2643
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
2644
 
 
2645
        // Align 32x32 tiles to the left top corner of the shared area
 
2646
        const RECT shared = m_server->GetSharedRect();
 
2647
        const int leftAligned = ((rect.left - shared.left) & 0xFFFFFFE0) + shared.left;
 
2648
        const int topAligned = ((rect.top - shared.top) & 0xFFFFFFE0) + shared.top;
 
2649
 
 
2650
        RECT rowRect = rect;    // we'll need left and right borders
 
2651
 
 
2652
        for (int y = topAligned; y < rect.bottom; y += 32)
 
2653
        {
 
2654
                const int tile_h = Min(rect.bottom - y, 32);
 
2655
// TODO: refactor it
 
2656
                int sl = scanLine;
 
2657
// window captions suffer an arbitrary scanline...
 
2658
                if (y == topAligned)
 
2659
                        sl = 31;
 
2660
                sl = Min(sl, tile_h-1);
 
2661
                const int scan_y = y + sl;
 
2662
 
 
2663
                _ASSERTE(scan_y >= rect.top);
 
2664
                _ASSERTE(scan_y < rect.bottom);
 
2665
 
 
2666
                rowRect.top = scan_y;
 
2667
                rowRect.bottom = scan_y + 1;
 
2668
                CaptureScreen(rowRect, m_mainbuff);
 
2669
                const int offset = (scan_y-m_bmrect.top) * m_bytesPerRow + (leftAligned-m_bmrect.left) * bytesPerPixel;
 
2670
                const unsigned char *o_ptr = m_backbuff + offset;
 
2671
                const unsigned char *n_ptr = m_mainbuff + offset;
 
2672
                for (int x = leftAligned; x < rect.right; x += 32)
 
2673
                {
 
2674
                        const int tile_w = Min(rect.right - x, 32);
 
2675
                        const int nBytes = tile_w * bytesPerPixel;
 
2676
                        if (memcmp(o_ptr, n_ptr, nBytes) != 0)
 
2677
                        {
 
2678
                                RECT tileRect;
 
2679
                                tileRect.left = x;
 
2680
                                tileRect.top = y;
 
2681
                                tileRect.right = x + tile_w;
 
2682
                                tileRect.bottom = y + tile_h;
 
2683
                                m_changed_rgn.AddRect(tileRect);
 
2684
                        }
 
2685
                        o_ptr += nBytes;
 
2686
                        n_ptr += nBytes;
 
2687
                }
 
2688
        }
 
2689
}
 
2690
 
 
2691
inline RECT MoveRect(RECT const& sr, POINT const& mv)
 
2692
{
 
2693
        RECT R;
 
2694
        R.left = sr.left + mv.x;
 
2695
        R.top = sr.top + mv.y;
 
2696
        R.right = sr.right + mv.x;
 
2697
        R.bottom = sr.bottom + mv.y;
 
2698
        return R;
 
2699
}
 
2700
 
 
2701
void vncDesktop::CopyRect(RECT const &rcDest, POINT ptSrc)
 
2702
{
 
2703
// motion vector
 
2704
        POINT mv2;
 
2705
        mv2.x = rcDest.left - ptSrc.x;
 
2706
        mv2.y = rcDest.top - ptSrc.y;
 
2707
 
 
2708
        // Clip the destination to the screen
 
2709
        RECT rcDr2;
 
2710
        const RECT r = m_server->GetSharedRect();
 
2711
        if (!IntersectRect(&rcDr2, &rcDest, &r))
 
2712
                return;
 
2713
 
 
2714
// NOTE: this is important.
 
2715
// each pixel in rcDr2 is either salvaged by copyrect
 
2716
// or became dirty
 
2717
        m_changed_rgn.AddRect(rcDr2);
 
2718
 
 
2719
        // Adjust the source correspondingly
 
2720
        ptSrc.x = rcDr2.left - mv2.x;
 
2721
        ptSrc.y = rcDr2.top - mv2.y;
 
2722
 
 
2723
        // Work out the source rectangle
 
2724
        RECT rcSource;
 
2725
        rcSource.left = ptSrc.x;
 
2726
        rcSource.top = ptSrc.y;
 
2727
        rcSource.right = rcSource.left + rcDr2.right - rcDr2.left;
 
2728
        rcSource.bottom = rcSource.top + rcDr2.bottom - rcDr2.top;
 
2729
 
 
2730
        // Clip the source to the screen
 
2731
        RECT rcSr2;
 
2732
        if (!IntersectRect(&rcSr2, &rcSource, &r))
 
2733
                return;
 
2734
 
 
2735
        rcDr2 = MoveRect(rcSr2, mv2);
 
2736
 
 
2737
// we'd try to continue the chain
 
2738
        if (m_copyrect_set)
 
2739
        {
 
2740
// prev motion vector
 
2741
                POINT mv1;
 
2742
                mv1.x = m_copyrect_rect.left - m_copyrect_src.x;
 
2743
                mv1.y = m_copyrect_rect.top - m_copyrect_src.y;
 
2744
 
 
2745
                m_changed_rgn.AddRect(m_copyrect_rect);
 
2746
 
 
2747
                RECT CR1i2Dst;
 
2748
                if (!IntersectRect(&CR1i2Dst, &m_copyrect_rect, &rcSr2))
 
2749
                {
 
2750
                        m_copyrect_set = FALSE;
 
2751
                        return;
 
2752
                }
 
2753
 
 
2754
                RECT rcDr3 = MoveRect(CR1i2Dst, mv2);
 
2755
                if (rcDr3.right - rcDr3.left >= 16 &&
 
2756
                        rcDr3.bottom - rcDr3.top >= 16)
 
2757
                {
 
2758
                        m_changed_rgn.SubtractRect(rcDr3);
 
2759
 
 
2760
                        POINT ptCR1i2Src;
 
2761
                        ptCR1i2Src.x = CR1i2Dst.left - mv1.x;
 
2762
                        ptCR1i2Src.y = CR1i2Dst.top - mv1.y;
 
2763
 
 
2764
                        m_copyrect_rect = rcDr3;
 
2765
                        m_copyrect_src = ptCR1i2Src;
 
2766
 
 
2767
                        //DPF(("CopyRect-cont: (%d, %d) (%d, %d, %d, %d)\n",
 
2768
                        //      m_copyrect_src.x,
 
2769
                        //      m_copyrect_src.y,
 
2770
                        //      m_copyrect_rect.left,
 
2771
                        //      m_copyrect_rect.top,
 
2772
                        //      m_copyrect_rect.right,
 
2773
                        //      m_copyrect_rect.bottom));
 
2774
                }
 
2775
                else
 
2776
                {
 
2777
                        m_copyrect_set = FALSE;
 
2778
                }
 
2779
        }
 
2780
        else
 
2781
        {
 
2782
                if (rcDr2.right - rcDr2.left >= 16 &&
 
2783
                        rcDr2.bottom - rcDr2.top >= 16)
 
2784
                {
 
2785
                        m_changed_rgn.SubtractRect(rcDr2);
 
2786
 
 
2787
                        m_copyrect_rect = rcDr2;
 
2788
                        m_copyrect_src.x = rcSr2.left;
 
2789
                        m_copyrect_src.y = rcSr2.top;
 
2790
                        m_copyrect_set = TRUE;
 
2791
 
 
2792
                        //DPF(("CopyRect: (%d, %d) (%d, %d, %d, %d)\n",
 
2793
                        //      m_copyrect_src.x,
 
2794
                        //      m_copyrect_src.y,
 
2795
                        //      m_copyrect_rect.left,
 
2796
                        //      m_copyrect_rect.top,
 
2797
                        //      m_copyrect_rect.right,
 
2798
                        //      m_copyrect_rect.bottom));
 
2799
                }
 
2800
        }
 
2801
}
 
2802
 
 
2803
void vncDesktop::CopyRectToBuffer(RECT dest, POINT source)
 
2804
{
 
2805
        const int ptsrc_re_vd_x = source.x - m_bmrect.left;
 
2806
        const int ptsrc_re_vd_y = source.y - m_bmrect.top;
 
2807
        _ASSERTE(ptsrc_re_vd_x >= 0);
 
2808
        _ASSERTE(ptsrc_re_vd_y >= 0);
 
2809
 
 
2810
        // Copy the data from one region of the back-buffer to another!
 
2811
        BYTE *srcptr = m_mainbuff + (ptsrc_re_vd_y * m_bytesPerRow) + (ptsrc_re_vd_x * m_scrinfo.format.bitsPerPixel/8);
 
2812
 
 
2813
        const int rcdest_re_vd_left = dest.left - m_bmrect.left;
 
2814
        const int rcdest_re_vd_top = dest.top - m_bmrect.top;
 
2815
        _ASSERTE(rcdest_re_vd_left >= 0);
 
2816
        _ASSERTE(rcdest_re_vd_top >= 0);
 
2817
 
 
2818
        BYTE *destptr = m_backbuff + (rcdest_re_vd_top * m_bytesPerRow) + (rcdest_re_vd_left * m_scrinfo.format.bitsPerPixel/8);
 
2819
        const UINT bytesPerLine = (dest.right - dest.left) * (m_scrinfo.format.bitsPerPixel/8);
 
2820
 
 
2821
        if (dest.top < source.y)
 
2822
        {
 
2823
                for (int y = dest.top; y < dest.bottom; y++)
 
2824
                {
 
2825
                        memmove(destptr, srcptr, bytesPerLine);
 
2826
                        srcptr += m_bytesPerRow;
 
2827
                        destptr += m_bytesPerRow;
 
2828
                }
 
2829
        }
 
2830
        else
 
2831
        {
 
2832
                srcptr += (m_bytesPerRow * ((dest.bottom - dest.top) - 1));
 
2833
                destptr += (m_bytesPerRow * ((dest.bottom - dest.top) - 1));
 
2834
                for (int y = dest.bottom; y > dest.top; y--)
 
2835
                {
 
2836
                        memmove(destptr, srcptr, bytesPerLine);
 
2837
                        srcptr -= m_bytesPerRow;
 
2838
                        destptr -= m_bytesPerRow;
 
2839
                }
 
2840
        }
 
2841
}
 
2842
 
 
2843
BOOL    IsBadDirectAccessConfig()
 
2844
{
 
2845
        if (IsWinVerOrHigher(5, 1))
 
2846
        {
 
2847
                if (GetSystemMetrics(SM_XVIRTUALSCREEN) < 0)
 
2848
                        return TRUE;
 
2849
                if (GetSystemMetrics(SM_YVIRTUALSCREEN) < 0)
 
2850
                        return TRUE;
 
2851
        }
 
2852
        return FALSE;
 
2853
}
 
2854
 
 
2855
BOOL vncDesktop::InitVideoDriver()
 
2856
{
 
2857
        // Mirror video drivers supported under Win2K, WinXP, WinVista
 
2858
        // and Windows NT 4.0 SP3 (we assume SP6).
 
2859
        if (!vncService::IsWinNT())
 
2860
                return FALSE;
 
2861
 
 
2862
        // FIXME: Windows NT 4.0 support is broken and thus we disable it here.
 
2863
        if (!IsWinVerOrHigher(5, 0))
 
2864
                return FALSE;
 
2865
 
 
2866
        if (m_server->DontUseDriver())
 
2867
        {
 
2868
                vnclog.Print(LL_STATE, VNCLOG("not activating video driver interface\n"));
 
2869
                return FALSE;
 
2870
        }
 
2871
 
 
2872
        BOOL    bIsBadDASDConfig = IsBadDirectAccessConfig();
 
2873
        if (bIsBadDASDConfig)
 
2874
        {
 
2875
                vnclog.Print(LL_INTINFO, VNCLOG("can't set direct access mode in this configuration of monitors due to a known Windows bug.\n"));
 
2876
        }
 
2877
 
 
2878
        BOOL    bSolicitDASD = m_server->DriverDirectAccess() & !bIsBadDASDConfig;
 
2879
 
 
2880
        _ASSERTE(!m_videodriver);
 
2881
        m_videodriver = new vncVideoDriver;
 
2882
        if (!m_videodriver)
 
2883
        {
 
2884
                vnclog.Print(LL_INTERR, VNCLOG("failed to create vncVideoDriver object\n"));
 
2885
                return FALSE;
 
2886
        }
 
2887
 
 
2888
        if (IsWinVerOrHigher(5, 0))
 
2889
        {
 
2890
// restart the driver if left running.
 
2891
// NOTE that on NT4 it must be running beforehand
 
2892
                if (m_videodriver->TestMapped())
 
2893
                {
 
2894
                        vnclog.Print(LL_INTINFO, VNCLOG("found abandoned Mirage driver running. restarting.\n"));
 
2895
                        m_videodriver->Deactivate();
 
2896
                }
 
2897
                _ASSERTE(!m_videodriver->TestMapped());
 
2898
        }
 
2899
 
 
2900
        {
 
2901
                RECT    vdesk_rect;
 
2902
                GetSourceDisplayRect(vdesk_rect);
 
2903
                (BOOL) m_videodriver->Activate(bSolicitDASD, &vdesk_rect);
 
2904
        }
 
2905
 
 
2906
        if (!m_videodriver->CheckVersion())
 
2907
        {
 
2908
                vnclog.Print(LL_INTINFO, VNCLOG("******** PLEASE INSTALL NEWER VERSION OF MIRAGE DRIVER! ********\n"));
 
2909
// IMPORTANT: fail on NT46
 
2910
                if (IsNtVer(4, 0))
 
2911
                        return FALSE;
 
2912
        }
 
2913
 
 
2914
        if (m_videodriver->MapSharedbuffers(bSolicitDASD))
 
2915
        {
 
2916
                vnclog.Print(LL_INTINFO, VNCLOG("video driver interface activated\n"));
 
2917
        }
 
2918
        else
 
2919
        {
 
2920
                delete m_videodriver;
 
2921
                m_videodriver = NULL;
 
2922
                vnclog.Print(LL_INTERR, VNCLOG("failed to activate video driver interface\n"));
 
2923
                return FALSE;
 
2924
        }
 
2925
        _ASSERTE(bSolicitDASD == m_videodriver->IsDirectAccessInEffect());
 
2926
        return TRUE;
 
2927
}
 
2928
 
 
2929
void vncDesktop::ShutdownVideoDriver()
 
2930
{
 
2931
        if (m_videodriver == NULL)
 
2932
                return;
 
2933
        delete m_videodriver;
 
2934
        m_videodriver = NULL;
 
2935
        vnclog.Print(LL_INTINFO, VNCLOG("video driver interface deactivated\n"));
 
2936
}
 
2937
 
 
2938
void
 
2939
vncDesktop::UpdateBlankScreenTimer()
 
2940
{
 
2941
        BOOL active = m_server->GetBlankScreen();
 
2942
        if (active && !m_timer_blank_screen) {
 
2943
                m_timer_blank_screen = SetTimer(Window(), TIMER_BLANK_SCREEN, 50, NULL);
 
2944
        } else if (!active && m_timer_blank_screen) {
 
2945
                KillTimer(Window(), TIMER_BLANK_SCREEN);
 
2946
                m_timer_blank_screen = 0;
 
2947
                PostMessage(m_hwnd, WM_TIMER, TIMER_RESTORE_SCREEN, 0);
 
2948
        }
 
2949
}
 
2950
 
 
2951
void
 
2952
vncDesktop::BlankScreen(BOOL set)
 
2953
{
 
2954
        if (set) {
 
2955
                SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 1, NULL, 0);
 
2956
                SendMessage(GetDesktopWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
 
2957
        } else {
 
2958
                SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, NULL, 0);
 
2959
                SendMessage(GetDesktopWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);
 
2960
        }
 
2961
}
 
2962
 
 
2963
// created for debug purposes
 
2964
bool    SaveBitmapToBMPFile(
 
2965
                        HANDLE hFile,
 
2966
                        void *ptrBm,
 
2967
                        void *ptrPal,
 
2968
                        int bmwidth,
 
2969
                        int bmheight,
 
2970
                        int bmstride,
 
2971
                        int bmclrdepth)
 
2972
{
 
2973
        BITMAPINFOHEADER bih = {0};
 
2974
        bih.biSize                      = sizeof(bih);
 
2975
        bih.biWidth                     = bmwidth;
 
2976
        bih.biHeight            = bmheight;
 
2977
        bih.biPlanes            = 1;
 
2978
        bih.biCompression       = BI_RGB;
 
2979
 
 
2980
        DWORD bitFields[3] = {0, 0, 0};
 
2981
 
 
2982
        if (bmclrdepth == 1)
 
2983
        {
 
2984
                bih.biBitCount = 1;
 
2985
                bih.biClrUsed = 2;
 
2986
        }
 
2987
        else if (bmclrdepth == 2)
 
2988
        {
 
2989
                bih.biBitCount = 2;
 
2990
                bih.biClrUsed = 4;
 
2991
        }
 
2992
        else if (bmclrdepth == 4)
 
2993
        {
 
2994
                bih.biBitCount = 4;
 
2995
                bih.biClrUsed = 0x10;
 
2996
        }
 
2997
        else if (bmclrdepth == 8)
 
2998
        {
 
2999
                bih.biBitCount = 8;
 
3000
                bih.biClrUsed = 0x100;
 
3001
        }
 
3002
        else if (bmclrdepth == 16)
 
3003
        {
 
3004
                bih.biBitCount = 16;
 
3005
                bih.biCompression = BI_BITFIELDS;
 
3006
// TODO: use actual masks
 
3007
                bitFields[0] = 0xF800;
 
3008
                bitFields[1] = 0x07E0;
 
3009
                bitFields[2] = 0x001F;
 
3010
        }
 
3011
        else if (bmclrdepth == 24)
 
3012
        {
 
3013
                bih.biBitCount = 24;
 
3014
        }
 
3015
        else if (bmclrdepth == 32)
 
3016
        {
 
3017
                bih.biBitCount = 32;
 
3018
        }
 
3019
        else
 
3020
                _ASSERTE(false);
 
3021
 
 
3022
        BITMAPFILEHEADER bfh = {0};
 
3023
        bfh.bfType                      = 0x4d42;       // 0x42 = "B" 0x4d = "M" 
 
3024
        bfh.bfOffBits           = sizeof(BITMAPFILEHEADER) + bih.biSize;
 
3025
 
 
3026
        if (bih.biClrUsed)
 
3027
        {
 
3028
                bfh.bfOffBits += bih.biClrUsed * sizeof(RGBQUAD);
 
3029
        }
 
3030
        else if (bitFields[0] || bitFields[1] || bitFields[2])
 
3031
        {
 
3032
                bfh.bfOffBits += sizeof(bitFields);
 
3033
        }
 
3034
 
 
3035
        unsigned lineSize = (((bih.biWidth * bih.biBitCount) + 15) / 8) & ~1;
 
3036
        bfh.bfSize = bfh.bfOffBits + lineSize * bih.biHeight; 
 
3037
 
 
3038
        ULONG ulnWr = 0;
 
3039
        if (!WriteFile(hFile, &bfh, sizeof(bfh), &ulnWr, NULL) || ulnWr!=sizeof(bfh))
 
3040
                return false;
 
3041
        if (!WriteFile(hFile, &bih, sizeof(bih), &ulnWr, NULL) || ulnWr!=sizeof(bih))
 
3042
                return false;
 
3043
 
 
3044
        if (ptrPal)
 
3045
        {
 
3046
                if (!WriteFile(hFile, ptrPal, bih.biClrUsed * sizeof(RGBQUAD), &ulnWr, NULL) || ulnWr!=bih.biClrUsed * sizeof(RGBQUAD))
 
3047
                        return false;
 
3048
        }
 
3049
        else if (bih.biCompression == BI_BITFIELDS)
 
3050
        {
 
3051
                if (!WriteFile(hFile, bitFields, sizeof(bitFields), &ulnWr, NULL) || ulnWr!=sizeof(bitFields))
 
3052
                        return false;
 
3053
        }
 
3054
 
 
3055
        for (int i = 0; i < bih.biHeight; i++)
 
3056
        {
 
3057
                char *pDWr = (char*)ptrBm + (bih.biHeight - i - 1) * bmstride;
 
3058
                if (!WriteFile(hFile, pDWr, lineSize, &ulnWr, NULL) || ulnWr!=lineSize)
 
3059
                        return false;
 
3060
        }
 
3061
 
 
3062
        return true;
 
3063
}
 
3064
 
 
3065
// created for debug purposes
 
3066
bool    bDbgBmDump(
 
3067
                        void *ptr,
 
3068
                        int bmwidth,
 
3069
                        int bmheight,
 
3070
                        int bmstride,
 
3071
                        int bmclrdepth)
 
3072
{
 
3073
        if (bmclrdepth!=16 && bmclrdepth!=32)
 
3074
        {
 
3075
                // TODO: add 8 bpp
 
3076
                return false;
 
3077
        }
 
3078
 
 
3079
        SYSTEMTIME stm;
 
3080
        GetSystemTime(&stm);
 
3081
        TCHAR szFileName[MAX_PATH];
 
3082
        sprintf(
 
3083
                szFileName,
 
3084
                "%04u.%02u.%02u-%02u-%02u-%02u-0x%08x.bmp",
 
3085
                stm.wYear, stm.wMonth, stm.wDay,
 
3086
                stm.wHour, stm.wMinute, stm.wSecond,
 
3087
                (uint) ptr);
 
3088
 
 
3089
        HANDLE hFile = CreateFile(
 
3090
                szFileName,
 
3091
                FILE_WRITE_DATA,
 
3092
                0,
 
3093
                NULL,
 
3094
                CREATE_NEW,
 
3095
                FILE_ATTRIBUTE_NORMAL,
 
3096
                NULL);
 
3097
        if (hFile==INVALID_HANDLE_VALUE)
 
3098
        {
 
3099
                return false;
 
3100
        }
 
3101
 
 
3102
        bool b= SaveBitmapToBMPFile(
 
3103
                hFile,
 
3104
                ptr,
 
3105
                NULL,
 
3106
                bmwidth,
 
3107
                bmheight,
 
3108
                bmstride,
 
3109
                bmclrdepth);
 
3110
 
 
3111
        CloseHandle(hFile);
 
3112
        return b;
 
3113
}
 
3114
 
 
3115
// created for debug purposes
 
3116
bool    vncDesktop::bDbgDumpSurfBuffers(const RECT &rcl)
 
3117
{
 
3118
        const int c2rect_re_vd_top = rcl.top - m_bmrect.top;
 
3119
        const int c3rect_re_vd_left = rcl.left - m_bmrect.left;
 
3120
        _ASSERTE(c2rect_re_vd_top >= 0);
 
3121
        _ASSERTE(c3rect_re_vd_left >= 0);
 
3122
        const UINT bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
 
3123
        const int offset = c2rect_re_vd_top * m_bytesPerRow + c3rect_re_vd_left * bytesPerPixel;
 
3124
 
 
3125
        bool b1 = bDbgBmDump(
 
3126
                m_mainbuff+offset,
 
3127
                rcl.right - rcl.left,
 
3128
                rcl.bottom - rcl.top,
 
3129
                m_bytesPerRow,
 
3130
                m_scrinfo.format.bitsPerPixel);
 
3131
 
 
3132
        bool b2 = bDbgBmDump(
 
3133
                m_backbuff+offset,
 
3134
                rcl.right - rcl.left,
 
3135
                rcl.bottom - rcl.top,
 
3136
                m_bytesPerRow,
 
3137
                m_scrinfo.format.bitsPerPixel);
 
3138
        return b1 && b2;
 
3139
}