namespace PluggIt { D_DEBUG_DOMAIN( PluggIt_SourceWin32, "PluggIt/SourceWin32", "PluggIt Source Win32" ); class SourceWin32 extends Source, Runnable { private HINSTANCE m_hInstance; private HWND m_root; private HWND m_window; private DFBPoint m_position; private DFBDimension m_size; private HBITMAP m_bitmap; private void *m_pixels; private int m_pitch; private HBITMAP m_bitmap2; private void *m_pixels2; private int m_pitch2; private HDC m_window_dc; private HDC m_bitmap_dc; private HDC m_bitmap_dc2; private Thread *m_thread; private Updates m_updates; private pthread_mutex_t m_lock; private pthread_cond_t m_cond; public class Config extends Source::Config { friend class SourceWin32; public typedef enum { WINDOW_SELECTION_NONE, WINDOW_SELECTION_TITLE, WINDOW_SELECTION_INTERACTIVE } WindowSelection; private WindowSelection m_selection; private std::string m_title; private bool m_always_all; private int m_interval_all; private int m_interval_hot; public Config( WindowSelection selection, const std::string &title = std::string(), bool always_all = false, int interval_all = 400, int interval_hot = 100 ) { m_selection = selection; m_title = title; m_always_all = always_all; m_interval_all = interval_all; m_interval_hot = interval_hot; } }; private const Config &m_config_win32; public SourceWin32( View *view, const Config &config ) : Source( view, config ), m_updates(16), m_config_win32( config ) { D_DEBUG_AT( PluggIt_SourceWin32, "%s( %p )\n", __FUNCTION__, view ); m_hInstance = GetModuleHandle( NULL ); D_DEBUG_AT( PluggIt_SourceWin32, " -> hInstance %p\n", m_hInstance ); m_root = GetDesktopWindow(); switch (config.m_selection) { case Config::WINDOW_SELECTION_NONE: m_window = m_root; break; case Config::WINDOW_SELECTION_TITLE: m_window = findWindow( config.m_title ); if (m_window == 0) throw new Exception( "Could not find window with title containing '%s'\n", config.m_title.c_str() ); break; case Config::WINDOW_SELECTION_INTERACTIVE: pickWindow(); if (m_window == 0) throw new Exception( "Could not interactively pick a window\n" ); break; default: throw new Exception( "Invalid window selection method\n" ); } RECT rect; GetClientRect( m_window, &rect ); m_position.x = rect.left; m_position.y = rect.top; m_size.w = rect.right - rect.left; m_size.h = rect.bottom - rect.top; #define RECT_WIDTH 32 #define RECT_HEIGHT 32 for (int y=0; y m_size.w - 1) region.x2 = m_size.w - 1; if (region.y2 > m_size.h - 1) region.y2 = m_size.h - 1; m_all_rects.push_back( DFBRectangle(region) ); } } std::string t = getWindowTitle( m_window ); D_INFO( "Source/Win32: Window %d,%d-%ux%u, name '%s'\n", m_position.x, m_position.y, m_size.w, m_size.h, t.c_str() ); m_view->config( m_size ); m_window_dc = GetDC( m_window ); m_bitmap_dc = CreateCompatibleDC( m_window_dc ); m_bitmap_dc2 = CreateCompatibleDC( m_window_dc ); BITMAPINFO bitmap_info = {{ biSize: sizeof(BITMAPINFOHEADER), biWidth: m_size.w, biHeight: m_size.h, biPlanes: 1, biBitCount: 32, biCompression: BI_RGB, biSizeImage: 0, biXPelsPerMeter: 0, biYPelsPerMeter: 0, biClrUsed: 0, biClrImportant: 0, }}; m_bitmap = CreateDIBSection( m_window_dc, &bitmap_info, DIB_RGB_COLORS, &m_pixels, NULL, 0 ); m_bitmap2 = CreateDIBSection( m_window_dc, &bitmap_info, DIB_RGB_COLORS, &m_pixels2, NULL, 0 ); BITMAP bitmap; GetObject( m_bitmap, sizeof(BITMAP), &bitmap ); m_pitch = bitmap.bmWidthBytes; GetObject( m_bitmap2, sizeof(BITMAP), &bitmap ); m_pitch2 = bitmap.bmWidthBytes; SelectObject( m_bitmap_dc, m_bitmap ); SelectObject( m_bitmap_dc2, m_bitmap2 ); pthread_mutex_init( &m_lock, NULL ); pthread_cond_init( &m_cond, NULL ); /* Create the thread object. */ m_thread = new Thread( this, "SourceWin32" ); m_thread->start(); } virtual ~SourceWin32() { m_thread->interrupt(); m_thread->join(); delete m_thread; pthread_mutex_destroy( &m_lock ); pthread_cond_destroy( &m_cond ); DeleteDC( m_window_dc ); DeleteDC( m_bitmap_dc ); DeleteDC( m_bitmap_dc2 ); DeleteObject( m_bitmap ); DeleteObject( m_bitmap2 ); } private void run() { D_DEBUG_AT( PluggIt_SourceWin32, "%s()\n", __FUNCTION__ ); while (!m_thread->isInterrupted()) { pthread_mutex_lock( &m_lock ); while (m_updates.num_regions() == 0) pthread_cond_wait( &m_cond, &m_lock ); vector rects; m_updates.GetRectangles( rects ); const DFBRegion &bounding = m_updates.bounding(); D_DEBUG_AT( PluggIt_SourceWin32, " -> %4d,%4d-%4dx%4d (%d regions, %d rectangles)\n", DFB_RECTANGLE_VALS_FROM_REGION( &bounding ), m_updates.num_regions(), rects.size() ); /* * (4) Update TV */ m_view->update( rects, (void*)((char*) m_pixels2 + m_pitch2 * (m_size.h - 1)), - m_pitch2 ); m_updates.reset(); pthread_mutex_unlock( &m_lock ); } } /**********************************************************************************************************************/ private static std::string getWindowTitle( HWND window ) { char buf[1024] = { 0 }; GetWindowText( window, buf, sizeof(buf) ); D_DEBUG_AT( PluggIt_SourceWin32, "%s( %p ) -> '%s'\n", __FUNCTION__, window, buf ); return buf; } class EnumContext { public const std::string &title; public HWND window; public EnumContext( const std::string &title ) : title(title), window(0) {} }; private static BOOL CALLBACK enumWindowsProc( HWND hwnd, LPARAM lParam ) { EnumContext *ctx = reinterpret_cast( lParam ); D_DEBUG_AT( PluggIt_SourceWin32, "%s( %p )\n", __FUNCTION__, hwnd ); std::string title = getWindowTitle( hwnd ); if (title == ctx->title || title.find( ctx->title ) < title.size()) ctx->window = hwnd; return ctx->window == NULL; } private HWND findWindow( const std::string &title ) { D_DEBUG_AT( PluggIt_SourceWin32, "%s( %s )\n", __FUNCTION__, title.c_str() ); EnumContext ctx( title ); EnumWindows( enumWindowsProc, reinterpret_cast( &ctx ) ); return ctx.window; } /**********************************************************************************************************************/ static LRESULT CALLBACK WndProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam ) // second message parameter { static SourceWin32 *thiz; POINT point; CREATESTRUCT *create; switch (uMsg) { case WM_CREATE: create = reinterpret_cast( lParam ); thiz = reinterpret_cast( create->lpCreateParams ); SetCursor( LoadCursor( NULL, IDC_CROSS ) ); break; case WM_LBUTTONDOWN: ShowWindow( hwnd, SW_HIDE ); GetCursorPos( &point ); D_DEBUG_AT( PluggIt_SourceWin32, " -> Cursor position is %ld,%ld\n", point.x, point.y ); thiz->m_window = WindowFromPoint( point ); if (thiz->m_window) { HWND parent; while ((parent = GetParent( thiz->m_window )) != NULL) thiz->m_window = parent; } D_DEBUG_AT( PluggIt_SourceWin32, " -> Window at cursor is %p: %s\n", thiz->m_window, getWindowTitle( thiz->m_window ).c_str() ); DestroyWindow( hwnd ); break; case WM_TIMER: if (wParam == 666) DestroyWindow( hwnd ); break; case WM_DESTROY: KillTimer( hwnd, 666 ); PostQuitMessage( 0 ); break; default: SetTimer( hwnd, 666, 5000, NULL ); return DefWindowProc( hwnd, uMsg, wParam, lParam ); } return 0; } private void pickWindow() { D_DEBUG_AT( PluggIt_SourceWin32, "%s()\n", __FUNCTION__ ); HDC hdc; hdc = GetDC( NULL ); if (!hdc) throw new Exception( "GetDC() returned NULL" ); RECT rect; GetClipBox( hdc, &rect ); D_DEBUG_AT( PluggIt_SourceWin32, " -> Desktop size: %ldx%ld\n", rect.right - rect.left, rect.bottom - rect.top ); ReleaseDC( NULL, hdc ); WNDCLASSEX wndClass; ZeroMemory( &wndClass, sizeof(wndClass) ); wndClass.cbSize = sizeof(wndClass); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = m_hInstance; wndClass.hIcon = NULL; wndClass.hIconSm = NULL; wndClass.hCursor = LoadCursor( NULL, IDC_UPARROW ); wndClass.hbrBackground = (HBRUSH) GetStockObject( NULL_BRUSH ); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = "GrabWindow"; if (!RegisterClassEx( &wndClass )) throw new Exception( "RegisterClassEx() failed!\n" ); AdjustWindowRect( &rect, WS_CAPTION, FALSE ); HWND grabwin; grabwin = CreateWindowEx( 0, "GrabWindow", "GrabWindow", WS_POPUP,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, m_hInstance, this ); SetWindowLong( grabwin, GWL_EXSTYLE, GetWindowLong( grabwin, GWL_EXSTYLE ) | WS_EX_TRANSPARENT | WS_EX_TOPMOST ); ShowWindow( grabwin, SW_SHOW ); MSG msg; while (GetMessage( &msg, 0, 0, 0 )) { TranslateMessage( &msg ); D_DEBUG_AT( PluggIt_SourceWin32, " -> Dispatching event (id %u)...\n", msg.message ); DispatchMessage( &msg ); } } /**********************************************************************************************************************/ private bool diffRect( const DFBRectangle_C &rect ) { D_DEBUG_AT( PluggIt_SourceWin32, "(2) comparing %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &rect ) ); DFBRegion region( rect ); for (int y = region.y1; y <= region.y2; y++) { const u64 *p1 = (const u64*)( (const u8*)m_pixels + (m_size.h - 1 - y) * m_pitch ); const u64 *p2 = (const u64*)( (const u8*)m_pixels2 + (m_size.h - 1 - y) * m_pitch2 ); for (int x = region.x1/2; x <= region.x2/2; x++) { if (p1[x] != p2[x]) return true; } } return false; } private vector m_all_rects; private vector m_hot_rects; public virtual int MainLoop() { long long last_all = 0; while (true) { bool all = true; const vector *copy_rects; if (m_config_win32.m_always_all) { usleep( m_config_win32.m_interval_all * 1000 ); copy_rects = &m_all_rects; } else { long long this_time = direct_clock_get_abs_millis(); if (this_time - last_all >= m_config_win32.m_interval_all) { last_all = this_time; copy_rects = &m_all_rects; } else { if (m_hot_rects.empty()) { usleep( 20000 ); continue; } else usleep( m_config_win32.m_interval_hot * 1000 ); copy_rects = &m_hot_rects; all = false; } } /* * (1) Copy from desktop to bitmap */ if (all) { D_DEBUG_AT( PluggIt_SourceWin32, "(1) copying all %4d,%4d-%4dx%4d\n", 0, 0, m_size.w, m_size.h ); BitBlt( m_bitmap_dc, 0, 0, m_size.w, m_size.h, m_window_dc, 0, 0, SRCCOPY ); } else { Updates copy( 32 ); for (unsigned int i=0; isize(); i++) { copy.addRegion( DFBRegion(copy_rects->at(i)) ); } vector rects; copy.GetRectangles( rects ); for (unsigned int i=0; i diff_rects; for (unsigned int i=0; isize(); i++) { if (diffRect( copy_rects->at(i) )) { diff_rects.push_back( copy_rects->at(i) ); } } /* * (3) Copy from bitmap to bitmap2 */ pthread_mutex_lock( &m_lock ); for (unsigned int i=0; i EXIT!\n" ); return 0; } }; }