namespace PluggIt { D_DEBUG_DOMAIN( PluggIt_Main, "PluggIt/Main", "PluggIt Main" ); D_DEBUG_DOMAIN( PluggIt_View, "PluggIt/View", "PluggIt View" ); #define NOTRCSOURCEMASK 0x20 #define HK_REMOTEAPP DIKS_CUSTOM97 class Main extends View, Runnable { class Config { public DFBDimension m_size; public DFBPoint m_offset; public DFBDimension m_resolution; public DFBLocation m_destination; public DFBSurfacePixelFormat m_format; public std::string m_title; public bool m_interactive; public long m_window; public bool m_always_all; public long m_interval_all; public long m_interval_hot; public long m_focus_timeout; public Config() : m_format(DSPF_UNKNOWN), m_interactive(false), m_window(0), m_always_all(false), m_interval_all(400), m_interval_hot(100), m_focus_timeout(0) { m_destination.x = 0.0f; m_destination.y = 0.0f; m_destination.w = 1.0f; m_destination.h = 1.0f; } }; private Config m_config; private Options m_options; private Scaler m_scaler; private IDirectFB m_dfb; private IDirectFBDisplayLayer m_layer; private IDirectFBWindow m_window; private IDirectFBSurface m_surface; private IDirectFBEventBuffer m_events; private Source *m_source; private DFBDimension m_source_resolution; private DFBDimension m_view_size; private DFBDimension m_view_resolution; private bool m_view_visible; private DFBSurfacePixelFormat m_view_format; private u8 m_opacity; private IDiVine *m_divine; public Main() : m_source(NULL), m_view_visible(false), m_opacity(255) { D_DEBUG_AT( PluggIt_Main, "%s()\n", __FUNCTION__ ); m_options.addOption( new Options::OptionDimension( "-s", "--size", "x", "Size of view", m_config.m_size ) ); m_options.addOption( new Options::OptionPoint ( "-o", "--offset", ",", "Offset of view", m_config.m_offset ) ); m_options.addOption( new Options::OptionDimension( "-r", "--resolution", "x", "Resolution of view", m_config.m_resolution ) ); m_options.addOption( new Options::OptionLocation ( "-d", "--destination", ",-x", "Destination location", m_config.m_destination ) ); m_options.addOption( new Options::OptionFormat ( "-f", "--format", "", "Pixel format of view", m_config.m_format ) ); m_options.addOption( new Options::OptionString ( "-t", "--title", "", "Title of window to show", m_config.m_title ) ); m_options.addOption( new Options::OptionBool ( "-i", "--interactive", "", "Use interactive window picking", m_config.m_interactive ) ); m_options.addOption( new Options::OptionLong ( "-w", "--window", "", "Pick window by id", m_config.m_window ) ); m_options.addOption( new Options::OptionBool ( "-a", "--all", "", "Always all", m_config.m_always_all ) ); m_options.addOption( new Options::OptionLong ( "-A", "--inter-all", "", "Interval all", m_config.m_interval_all ) ); m_options.addOption( new Options::OptionLong ( "-H", "--inter-hot", "", "Interval hot", m_config.m_interval_hot ) ); m_options.addOption( new Options::OptionLong ( "-F", "--focus", "", "Focus timeout", m_config.m_focus_timeout ) ); } public void main( int argc, char *argv[] ) { D_DEBUG_AT( PluggIt_Main, "%s()\n", __FUNCTION__ ); try { /* Initialize DirectFB. */ DirectFB::Init( &argc, &argv ); if (!m_options.parseCommandLine( argc, argv )) return; initDFB(); DiVineCreate( &m_divine ); #ifdef __WIN32__ SourceWin32::Config config( m_config.m_interactive ? SourceWin32::Config::WINDOW_SELECTION_INTERACTIVE : (m_config.m_title.size() > 0 ? SourceWin32::Config::WINDOW_SELECTION_TITLE : SourceWin32::Config::WINDOW_SELECTION_NONE), m_config.m_title, m_config.m_always_all, m_config.m_interval_all, m_config.m_interval_hot ); m_source = new SourceWin32( this, config ); #else SourceX11::Config config( m_config.m_interactive ? SourceX11::Config::WINDOW_SELECTION_INTERACTIVE : (m_config.m_title.size() > 0 ? SourceX11::Config::WINDOW_SELECTION_TITLE : (m_config.m_window != 0 ? SourceX11::Config::WINDOW_SELECTION_ID : SourceX11::Config::WINDOW_SELECTION_NONE)), m_config.m_title, m_config.m_window ); m_source = new SourceX11( this, config ); #endif Thread *thread = new Thread( this, "Main" ); thread->start(); while (true) { DFBEvent event; m_events.WaitForEvent(); m_events.GetEvent( &event ); switch (event.clazz) { case DFEC_WINDOW: handleWindowEvent( &event.window ); break; default: break; } } } catch (DFBException *e) { cerr << endl; cerr << "Caught exception!" << endl; cerr << " ==> " << e << endl; } catch (Exception *e) { cerr << endl; cerr << "Caught exception!" << endl; cerr << " ==> " << e << endl; } } public void handleWindowEvent( const DFBWindowEvent *event ) { int key = -1; bool up = false; switch (event->type) { case DWET_KEYUP: up = true; case DWET_KEYDOWN: if (event->key_symbol == DIKS_0 && !up) { m_opacity = (m_opacity == 255 ? 0 : 255); m_window.SetOpacity( m_opacity ); } else key = CKeySend::MapDfbKeyEventToVK( event->key_symbol ); break; case DWET_LOSTFOCUS: if (m_config.m_focus_timeout) { sleep( m_config.m_focus_timeout ); hk_SendKey( HK_REMOTEAPP, 0, 0, 1 ); } break; default: break; } if (key != -1) { D_INFO( "Sending key %d (%s)\n", key, up ? "up" : "down" ); if (up) CKeySend::SendKeyUp( key ); else CKeySend::SendKeyDown( key ); } } private void initDFB() { D_DEBUG_AT( PluggIt_Main, "%s()\n", __FUNCTION__ ); /* Create the super interface. */ m_dfb = DirectFB::Create(); m_layer = m_dfb.GetDisplayLayer( DLID_PRIMARY ); m_events = m_dfb.CreateEventBuffer(); } private void run() { try { m_source->MainLoop(); } catch (DFBException *e) { cerr << endl; cerr << "Caught exception!" << endl; cerr << " ==> " << e << endl; } catch (Exception *e) { cerr << endl; cerr << "Caught exception!" << endl; cerr << " ==> " << e << endl; } } public virtual void config( DFBDimension &source_resolution ) { D_DEBUG_AT( PluggIt_View, "%s( %u, %u )\n", __FUNCTION__, source_resolution.w, source_resolution.h ); /* Ignore bogus events */ if (m_source_resolution == source_resolution) { D_DEBUG_AT( PluggIt_View, " -> unchanged source size\n" ); return; } m_source_resolution = source_resolution; /* Calculate view resolution */ DFBDimension resolution = m_config.m_resolution; if (!resolution.w) { if (!resolution.h) { resolution = source_resolution; D_DEBUG_AT( PluggIt_View, " -> no width/height\n" ); } else { resolution.w = resolution.h * source_resolution.w / source_resolution.h; D_DEBUG_AT( PluggIt_View, " -> no width\n" ); } } else if (!resolution.h) { resolution.h = resolution.w * source_resolution.h / source_resolution.w; D_DEBUG_AT( PluggIt_View, " -> no height\n" ); } D_DEBUG_AT( PluggIt_View, " -> resolution %ux%u\n", resolution.w, resolution.h ); /* Calculate view size */ DFBDimension size = m_config.m_size; if (!size.w) { if (!size.h) { size = resolution; D_DEBUG_AT( PluggIt_View, " -> no width/height\n" ); } else { size.w = size.h * resolution.w / resolution.h; D_DEBUG_AT( PluggIt_View, " -> no width\n" ); } } else if (!size.h) { size.h = size.w * resolution.h / resolution.w; D_DEBUG_AT( PluggIt_View, " -> no height\n" ); } D_DEBUG_AT( PluggIt_View, " -> %ux%u\n", size.w, size.h ); if (m_view_resolution == resolution) D_DEBUG_AT( PluggIt_View, " -> unchanged view resolution\n" ); if (m_view_size == size) { D_DEBUG_AT( PluggIt_View, " -> unchanged view size\n" ); return; } if (m_window) m_window.Resize( size.w, size.h ); else { /* Create the window. */ DFBWindowDescription desc; desc.flags = (DFBWindowDescriptionFlags)( DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_PIXELFORMAT ); desc.posx = 0; desc.posy = 0; desc.width = size.w; desc.height = size.h; desc.pixelformat = m_config.m_format; m_window = m_layer.CreateWindow( desc ); m_surface = m_window.GetSurface(); m_view_format = m_surface.GetPixelFormat(); m_window.AttachEventBuffer( m_events ); DFBWindowGeometry geometry; geometry.mode = DWGM_LOCATION; geometry.location = m_config.m_destination; m_window.SetDstGeometry( &geometry ); } m_view_size = size; m_view_resolution = resolution; D_DEBUG_AT( PluggIt_View, " -> view size %4ux%4u\n", m_view_size.w, m_view_size.h ); D_DEBUG_AT( PluggIt_View, " -> view resolution %4ux%4u\n", m_view_resolution.w, m_view_resolution.h ); D_DEBUG_AT( PluggIt_View, " -> source resolution %4ux%4u\n", m_source_resolution.w, m_source_resolution.h ); } public virtual void update( const vector &rects, void *ptr, int pitch ) { unsigned int i; DFBRegion clip( m_view_size ); const DFBPoint &offset = m_config.m_offset; bool first = true; DFBRegion flip; D_DEBUG_AT( PluggIt_View, "%s( [%zd], %p, %d )\n", __FUNCTION__, rects.size(), ptr, pitch ); D_ASSERT( rects.size() > 0 ); D_ASSERT( ptr != NULL ); // m_dfb.WaitIdle(); if (m_source_resolution == m_view_resolution) { D_DEBUG_AT( PluggIt_View, " -> unscaled %4dx%4d\n", m_source_resolution.w, m_source_resolution.h ); if (m_view_format == DSPF_RGB16) { int tp = ((m_view_size.w * 2) + 7) & ~7; void *tmp = malloc( tp * m_view_size.h ); for (i=0; i [%2d] %4d,%4d-%4dx%4d (original)\n", i, DFB_RECTANGLE_VALS( &rects[i] ) ); DFBRegion region( DFBRectangle(rects[i]) - offset ); D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (translated)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); ptr = (void*)((char*) ptr + offset.x * 4 + offset.y * pitch); /* Clip update against our resolution */ if (dfb_region_region_intersect( ®ion, &clip )) { D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (clipped update)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); DFBRectangle rect( region ); dfb_convert_to_rgb16( DSPF_RGB32, (void*)((char*) ptr + rect.x * 4 + rect.y * pitch), pitch, m_view_size.h, (u16*) tmp, tp, rect.w, rect.h ); m_surface.Write( (char*) tmp + DFB_BYTES_PER_LINE( m_view_format, region.x1 ) + region.y1 * tp, tp, &rect ); if (first) { first = false; flip = region; } else flip.unionWith( region ); //m_surface.Flip( ®ion ); } } free( tmp ); } else { for (i=0; i [%2d] %4d,%4d-%4dx%4d (original)\n", i, DFB_RECTANGLE_VALS( &rects[i] ) ); DFBRegion region( DFBRectangle(rects[i]) - offset ); D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (translated)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); ptr = (void*)((char*) ptr + offset.x * 4 + offset.y * pitch); /* Clip update against our resolution */ if (dfb_region_region_intersect( ®ion, &clip )) { D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (clipped update)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); DFBRectangle rect( region ); if (m_view_format == DSPF_ARGB) { u32 *p = (u32*)((char*) ptr + rect.x * 4 + rect.y * pitch); for (int y=0; y Write...\n" ); m_surface.Write( (char*) ptr + DFB_BYTES_PER_LINE( m_view_format, region.x1 ) + region.y1 * pitch, pitch, &rect ); D_DEBUG_AT( PluggIt_View, " -> Write done.\n" ); if (first) { first = false; flip = region; } else flip.unionWith( region ); //m_surface.Flip( ®ion ); } } } } else { int tp = ((m_view_size.w * 4) + 7) & ~7; void *tmp = malloc( tp * m_view_size.h ); D_DEBUG_AT( PluggIt_View, " -> scaled %4dx%4d => %4dx%4d\n", m_source_resolution.w, m_source_resolution.h, m_view_resolution.w, m_view_resolution.h ); for (i=0; i [%2d] %4d,%4d-%4dx%4d (original)\n", i, DFB_RECTANGLE_VALS( &rects[i] ) ); DFBRegion region( DFBRectangle(rects[i]) - offset ); D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (translated)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); ptr = (void*)((char*) ptr + offset.x * 4 + offset.y * pitch); /* Transform source updates to view resolution */ region.x1 = region.x1 * m_view_resolution.w / m_source_resolution.w; region.y1 = region.y1 * m_view_resolution.h / m_source_resolution.h; region.x2 = region.x2 * m_view_resolution.w / m_source_resolution.w; region.y2 = region.y2 * m_view_resolution.h / m_source_resolution.h; if (region.x1 > 0) region.x1--; if (region.y1 > 0) region.y1--; if (region.x2 < m_view_resolution.w-1) region.x2++; if (region.x2 < m_view_resolution.w-1) region.x2++; if (region.y2 < m_view_resolution.h-1) region.y2++; if (region.y2 < m_view_resolution.h-1) region.y2++; D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (scaled)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); /* Clip update against our resolution */ if (dfb_region_region_intersect( ®ion, &clip )) { D_DEBUG_AT( PluggIt_View, " -> %4d,%4d-%4dx%4d (clipped)\n", DFB_RECTANGLE_VALS_FROM_REGION( ®ion ) ); DFBRectangle rect( region ); m_scaler.scale( m_view_format, tmp, tp, ptr, pitch, m_source_resolution.w, m_source_resolution.h, m_view_resolution.w, m_view_resolution.h, region ); m_surface.Write( (char*) tmp + DFB_BYTES_PER_LINE( m_view_format, region.x1 ) + region.y1 * tp, tp, &rect ); if (first) { first = false; flip = region; } else flip.unionWith( region ); //m_surface.Flip( ®ion ); } } free( tmp ); } m_surface.Flip( &flip ); if (!m_view_visible) { m_window.SetOpacity( 0xff ); m_view_visible = true; } } void hk_SendKey( int keyname, int src, int sys, int cmd ) { if (m_divine) { DFBResult ret; DFBInputEvent event; src |= NOTRCSOURCEMASK; event.clazz = DFEC_INPUT; event.type = DIET_KEYPRESS; event.key_code = (((unsigned int)src & 0xff) << 24) | (((unsigned int)sys & 0xff) << 16) | ((unsigned int)cmd & 0xffff); event.key_symbol = (DFBInputDeviceKeySymbol)keyname; event.flags = (DFBInputEventFlags)(DIEF_KEYCODE | DIEF_KEYSYMBOL); ret = m_divine->SendEvent( m_divine, &event ); if (ret) D_DERROR( (DirectResult) ret, "IDiVine::SendEvent() failed!\n" ); } else D_ERROR( "IDiVine interface is null!\n" ); } }; }