static gint quit_event( GtkWidget *widget, gpointer data ) { intf_thread_t *p_intf = (intf_thread_t *)data; (void)widget; libvlc_Quit( p_intf->p_libvlc ); return TRUE; }
static void *SigThread (void *data) { intf_thread_t *obj = data; sigset_t set; int signum; sigemptyset (&set); if (!ignored (SIGHUP)) /* <- needed to handle nohup properly */ sigaddset (&set, SIGHUP); sigaddset (&set, SIGINT); sigaddset (&set, SIGQUIT); sigaddset (&set, SIGTERM); sigaddset (&set, SIGCHLD); do { while (sigwait (&set, &signum)); #ifdef __APPLE__ /* In Mac OS X up to 10.5 sigwait (among others) is not a pthread * cancellation point */ vlc_testcancel(); #endif /* Hack for Qt QProcess */ if (signum == SIGCHLD) { struct sigaction act; sigaction (signum, NULL, &act); if ((act.sa_flags & SA_SIGINFO) || (act.sa_handler != SIG_DFL)) { msg_Err (obj, "signal %d overriden (%p)", signum, act.sa_handler); #ifdef __GLIBC__ Dl_info info; if (dladdr (act.sa_handler, &info)) msg_Err (obj, " %s(%s)[%p]", info.dli_fname ? info.dli_fname : "?", info.dli_sname ? info.dli_sname : "?", info.dli_saddr); #endif if (!(act.sa_flags & SA_SIGINFO) && (act.sa_handler != SIG_IGN)) act.sa_handler (signum); } } } while (signum == SIGCHLD); msg_Err (obj, "Caught %s signal, exiting...", strsignal (signum)); libvlc_Quit (obj->p_libvlc); /* After 3 seconds, fallback to normal signal handling */ msleep (3 * CLOCK_FREQ); pthread_sigmask (SIG_UNBLOCK, &set, NULL); for (;;) pause (); }
/***************************************************************************** * Quit VLC *****************************************************************************/ static int vlclua_quit( lua_State *L ) { vlc_object_t *p_this = vlclua_get_this( L ); /* The rc.c code also stops the playlist ... not sure if this is needed * though. */ libvlc_Quit( p_this->p_libvlc ); return 0; }
MRESULT EXPENTRY OS2Factory::OS2FrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) { // Get pointer to thread info: should only work with the parent window intf_thread_t *p_intf = (intf_thread_t *)WinQueryWindowPtr( hwnd, 0 ); OS2Factory *pFactory = (OS2Factory*)OS2Factory::instance( p_intf ); if( msg == WM_ADJUSTWINDOWPOS ) { PSWP pswp = ( PSWP )PVOIDFROMMP( mp1 ); if( pswp->fl & ( SWP_MINIMIZE | SWP_RESTORE )) { // propagate to all the owned windows HENUM henum = WinBeginEnumWindows( HWND_DESKTOP ); HWND hwndNext; while(( hwndNext = WinGetNextWindow( henum )) != NULLHANDLE ) { if( WinQueryWindow( hwndNext, QW_OWNER ) == pFactory->m_hParentClientWindow ) WinSetWindowPos( hwndNext, 0, 0, 0, 0, 0, pswp->fl & ( SWP_MINIMIZE | SWP_RESTORE )); } } } else if( msg == WM_SYSCOMMAND ) { // If closing parent window if( SHORT1FROMMP(mp1) == SC_CLOSE ) { libvlc_Quit( p_intf->p_libvlc ); return 0; } else if( SHORT1FROMMP(mp1) == SC_MINIMIZE ) { pFactory->minimize(); return 0; } else if( SHORT1FROMMP(mp1) == SC_RESTORE ) { pFactory->restore(); return 0; } else { msg_Dbg( p_intf, "WM_SYSCOMMAND %i", (SHORT1FROMMP(mp1))); } } return pFactory->m_pfnwpOldFrameProc( hwnd, msg, mp1, mp2 ); }
static void LoopRequest( playlist_t *p_playlist ) { playlist_private_t *p_sys = pl_priv(p_playlist); assert( !p_sys->p_input ); /* No input. Several cases * - No request, running status -> start new item * - No request, stopped status -> collect garbage * - Request, running requested -> start new item * - Request, stopped requested -> collect garbage */ const int i_status = p_sys->request.b_request ? p_sys->request.i_status : p_sys->status.i_status; if( i_status == PLAYLIST_STOPPED || !vlc_object_alive( p_playlist ) ) { p_sys->status.i_status = PLAYLIST_STOPPED; if( p_sys->p_input_resource && input_resource_HasVout( p_sys->p_input_resource ) ) { /* XXX We can unlock if we don't issue the wait as we will be * call again without anything else done between the calls */ PL_UNLOCK; /* input_resource_t must be manipulated without playlist lock */ input_resource_TerminateVout( p_sys->p_input_resource ); PL_LOCK; } else { if( vlc_object_alive( p_playlist ) ) vlc_cond_wait( &p_sys->signal, &p_sys->lock ); } return; } playlist_item_t *p_item = NextItem( p_playlist ); if( p_item ) { msg_Dbg( p_playlist, "starting playback of the new playlist item" ); PlayItem( p_playlist, p_item ); return; } msg_Dbg( p_playlist, "nothing to play" ); p_sys->status.i_status = PLAYLIST_STOPPED; if( var_GetBool( p_playlist, "play-and-exit" ) ) { msg_Info( p_playlist, "end of playlist, exiting" ); libvlc_Quit( p_playlist->p_libvlc ); } }
/** * Cleanup a libvlc instance. The instance is not completely deallocated * \param p_libvlc the instance to clean */ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc ) { libvlc_priv_t *priv = libvlc_priv (p_libvlc); /* Ask the interfaces to stop and destroy them */ msg_Dbg( p_libvlc, "removing all interfaces" ); libvlc_Quit( p_libvlc ); intf_DestroyAll( p_libvlc ); #ifdef ENABLE_VLM /* Destroy VLM if created in libvlc_InternalInit */ if( priv->p_vlm ) { vlm_Delete( priv->p_vlm ); } #endif /* Free playlist now, all threads are gone */ playlist_t *p_playlist = libvlc_priv (p_libvlc)->p_playlist; if( p_playlist != NULL ) playlist_Destroy( p_playlist ); #if !defined( _WIN32 ) && !defined( __OS2__ ) char *pidfile = var_InheritString( p_libvlc, "pidfile" ); if( pidfile != NULL ) { msg_Dbg( p_libvlc, "removing PID file %s", pidfile ); if( unlink( pidfile ) ) msg_Warn( p_libvlc, "cannot remove PID file %s: %s", pidfile, vlc_strerror_c(errno) ); free( pidfile ); } #endif if (priv->parser != NULL) playlist_preparser_Delete(priv->parser); vlc_DeinitActions( p_libvlc, priv->actions ); /* Save the configuration */ if( !var_InheritBool( p_libvlc, "ignore-config" ) ) config_AutoSaveConfigFile( VLC_OBJECT(p_libvlc) ); /* Free module bank. It is refcounted, so we call this each time */ module_EndBank (true); vlc_LogDeinit (p_libvlc); #if defined(_WIN32) || defined(__OS2__) system_End( ); #endif }
void CmdQuit::execute() { if( getIntf()->p_sys->p_input ) { vout_thread_t *pVout = input_GetVout( getIntf()->p_sys->p_input ); if( pVout ) { vout_OSDMessage( pVout, SPU_DEFAULT_CHANNEL, "%s", _( "Quit" ) ); vlc_object_release( pVout ); } } // Kill libvlc libvlc_Quit( getIntf()->p_libvlc ); }
/** * Run the main control thread itself */ static void *Thread ( void *data ) { playlist_t *p_playlist = data; playlist_private_t *p_sys = pl_priv(p_playlist); PL_LOCK; while( !p_sys->killed ) { /* Playlist in stopped state */ assert(p_sys->p_input == NULL); if( !p_sys->request.b_request ) { vlc_cond_wait( &p_sys->signal, &p_sys->lock ); continue; } while( !p_sys->killed && Next( p_playlist ) ) { /* Playlist in running state */ assert(p_sys->p_input != NULL); do LoopInput( p_playlist ); while( p_sys->p_input != NULL ); } msg_Dbg( p_playlist, "nothing to play" ); if( var_InheritBool( p_playlist, "play-and-exit" ) ) { msg_Info( p_playlist, "end of playlist, exiting" ); libvlc_Quit( p_playlist->p_libvlc ); } /* Destroy any video display now (XXX: ugly hack) */ if( input_resource_HasVout( p_sys->p_input_resource ) ) { PL_UNLOCK; /* Mind: NO LOCKS while manipulating input resources! */ input_resource_TerminateVout( p_sys->p_input_resource ); PL_LOCK; } } PL_UNLOCK; input_resource_Terminate( p_sys->p_input_resource ); return NULL; }
/***************************************************************************** * OpenDemux: initialize the target, ie. parse the command *****************************************************************************/ int OpenDemux ( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; char * psz_name = p_demux->psz_path; p_demux->pf_control = DemuxControl; p_demux->p_sys = NULL; /* Check for a "vlc://nop" command */ if( !strcasecmp( psz_name, "nop" ) ) { msg_Info( p_demux, "command `nop'" ); p_demux->pf_demux = DemuxNoOp; return VLC_SUCCESS; } /* Check for a "vlc://quit" command */ if( !strcasecmp( psz_name, "quit" ) ) { msg_Info( p_demux, "command `quit'" ); p_demux->pf_demux = DemuxNoOp; libvlc_Quit( p_demux->p_libvlc ); return VLC_SUCCESS; } /* Check for a "vlc://pause:***" command */ if( !strncasecmp( psz_name, "pause:", 6 ) ) { double f = us_atof( psz_name + 6 ); mtime_t end = mdate() + f * (mtime_t)1000000; msg_Info( p_demux, "command `pause %f'", f ); p_demux->pf_demux = DemuxPause; p_demux->p_sys = malloc( sizeof( end ) ); if( p_demux->p_sys == NULL ) return VLC_ENOMEM; memcpy( p_demux->p_sys, &end, sizeof( end ) ); return VLC_SUCCESS; } msg_Err( p_demux, "unknown command `%s'", psz_name ); return VLC_EGENERIC; }
/***************************************************************************** * Run: interface thread *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { intf_sys_t sys; SERVICE_TABLE_ENTRY dispatchTable[] = { { (LPTSTR)VLCSERVICENAME, &ServiceDispatch }, { NULL, NULL } }; int canc = vlc_savecancel(); p_global_intf = p_intf; p_intf->p_sys = &sys; p_intf->p_sys->psz_service = var_InheritString( p_intf, "ntservice-name" ); p_intf->p_sys->psz_service = p_intf->p_sys->psz_service ? p_intf->p_sys->psz_service : strdup(VLCSERVICENAME); if( var_InheritBool( p_intf, "ntservice-install" ) ) { NTServiceInstall( p_intf ); return; } if( var_InheritBool( p_intf, "ntservice-uninstall" ) ) { NTServiceUninstall( p_intf ); return; } if( StartServiceCtrlDispatcher( dispatchTable ) == 0 ) { msg_Err( p_intf, "StartServiceCtrlDispatcher failed" ); /* str review */ } free( p_intf->p_sys->psz_service ); /* Make sure we exit (In case other interfaces have been spawned) */ libvlc_Quit( p_intf->p_libvlc ); vlc_restorecancel( canc ); }
/***************************************************************************** * Run: interface thread *****************************************************************************/ static void *Run( void *data ) { intf_thread_t *p_intf = data; SERVICE_TABLE_ENTRY dispatchTable[] = { { TEXT(VLCSERVICENAME), &ServiceDispatch }, { NULL, NULL } }; p_global_intf = p_intf; p_intf->p_sys->psz_service = var_InheritString( p_intf, "ntservice-name" ); p_intf->p_sys->psz_service = p_intf->p_sys->psz_service ? p_intf->p_sys->psz_service : strdup(VLCSERVICENAME); if( var_InheritBool( p_intf, "ntservice-install" ) ) { NTServiceInstall( p_intf ); return NULL; } if( var_InheritBool( p_intf, "ntservice-uninstall" ) ) { NTServiceUninstall( p_intf ); return NULL; } if( StartServiceCtrlDispatcher( dispatchTable ) == 0 ) { msg_Err( p_intf, "StartServiceCtrlDispatcher failed" ); /* str review */ } free( p_intf->p_sys->psz_service ); /* Make sure we exit (In case other interfaces have been spawned) */ libvlc_Quit( p_intf->p_libvlc ); return NULL; }
static void LoopRequest( playlist_t *p_playlist, int i_status ) { playlist_private_t *p_sys = pl_priv(p_playlist); assert( !p_sys->p_input ); /* No input. Several cases * - No request, running status -> start new item * - No request, stopped status -> collect garbage * - Request, running requested -> start new item * - Request, stopped requested -> collect garbage */ if( i_status == PLAYLIST_STOPPED ) { p_sys->status.i_status = PLAYLIST_STOPPED; vlc_cond_wait( &p_sys->signal, &p_sys->lock ); return; } playlist_item_t *p_item = NextItem( p_playlist ); if( p_item ) { msg_Dbg( p_playlist, "starting playback of the new playlist item" ); ResyncCurrentIndex( p_playlist, p_item ); PlayItem( p_playlist, p_item ); return; } msg_Dbg( p_playlist, "nothing to play" ); p_sys->status.i_status = PLAYLIST_STOPPED; if( var_InheritBool( p_playlist, "play-and-exit" ) ) { msg_Info( p_playlist, "end of playlist, exiting" ); libvlc_Quit( p_playlist->p_libvlc ); } }
void DialogsProvider::quit() { b_isDying = true; libvlc_Quit( p_intf->p_libvlc ); }
/** * Cleanup a libvlc instance. The instance is not completely deallocated * \param p_libvlc the instance to clean */ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc ) { libvlc_priv_t *priv = libvlc_priv (p_libvlc); playlist_t *p_playlist = libvlc_priv (p_libvlc)->p_playlist; /* Deactivate the playlist */ msg_Dbg( p_libvlc, "deactivating the playlist" ); pl_Deactivate( p_libvlc ); /* Remove all services discovery */ msg_Dbg( p_libvlc, "removing all services discovery tasks" ); playlist_ServicesDiscoveryKillAll( p_playlist ); /* Ask the interfaces to stop and destroy them */ msg_Dbg( p_libvlc, "removing all interfaces" ); libvlc_Quit( p_libvlc ); intf_DestroyAll( p_libvlc ); #ifdef ENABLE_VLM /* Destroy VLM if created in libvlc_InternalInit */ if( priv->p_vlm ) { vlm_Delete( priv->p_vlm ); } #endif #if defined(MEDIA_LIBRARY) media_library_t* p_ml = priv->p_ml; if( p_ml ) { ml_Destroy( VLC_OBJECT( p_ml ) ); vlc_object_release( p_ml ); libvlc_priv(p_playlist->p_libvlc)->p_ml = NULL; } #endif /* Free playlist now, all threads are gone */ playlist_Destroy( p_playlist ); msg_Dbg( p_libvlc, "removing stats" ); #if !defined( WIN32 ) && !defined( __OS2__ ) char* psz_pidfile = NULL; if( b_daemon ) { psz_pidfile = var_CreateGetNonEmptyString( p_libvlc, "pidfile" ); if( psz_pidfile != NULL ) { msg_Dbg( p_libvlc, "removing pid file %s", psz_pidfile ); if( unlink( psz_pidfile ) == -1 ) { msg_Dbg( p_libvlc, "removing pid file %s: %m", psz_pidfile ); } } free( psz_pidfile ); } #endif /* Save the configuration */ if( !var_InheritBool( p_libvlc, "ignore-config" ) ) config_AutoSaveConfigFile( VLC_OBJECT(p_libvlc) ); /* Free module bank. It is refcounted, so we call this each time */ module_EndBank (true); vlc_DeinitActions( p_libvlc, priv->actions ); }
static LRESULT HandleCadMessage(intf_thread_t* p_intf, HWND hwnd, WPARAM wParam, LPARAM lParam) { intf_sys_t* const p_sys = p_intf->p_sys; switch (lParam) { case IPC_PLAY: { playlist_Play(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_PLAYPAUSE: { playlist_t* p_playlist = pl_Get(p_intf->p_libvlc); const bool playing = playlist_Status(p_playlist) == PLAYLIST_RUNNING; playlist_Control(p_playlist, playing ? PLAYLIST_PAUSE : PLAYLIST_PLAY, pl_Unlocked); return 1; } case IPC_PAUSE: { playlist_Pause(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_STOP: { playlist_Stop(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_NEXT: { playlist_Next(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_PREVIOUS: { playlist_Prev(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_SET_VOLUME: { playlist_VolumeSet(pl_Get(p_intf->p_libvlc), (int)wParam / 100.0f); return 1; } case IPC_GET_VOLUME: { // VLC can return a volume larger than 100% so we need to cap it to 100 here. const float volume = playlist_VolumeGet(pl_Get(p_intf->p_libvlc)) * 100.0f; return (LRESULT)min(volume, 100.0f); } case IPC_GET_DURATION: { unsigned int duration = 0; if (p_sys->p_input) { input_item_t* const p_item = input_GetItem(p_sys->p_input); duration = (unsigned int)(input_item_GetDuration(p_item) / 1000000); } return duration; } case IPC_GET_POSITION: { int pos = 0; if (p_sys->p_input) { pos = (int)(var_GetTime(p_sys->p_input, "time") / CLOCK_FREQ); } return pos; } case IPC_SET_POSITION: { if (p_sys->p_input) { var_SetTime(p_sys->p_input, "time", (int64_t)wParam * CLOCK_FREQ); } return 0; } case IPC_GET_SHUFFLE: { return (int)var_GetBool(pl_Get(p_intf->p_libvlc), "random"); } case IPC_SET_SHUFFLE: { return (int)var_SetBool(pl_Get(p_intf->p_libvlc), "random", (bool)wParam); } case IPC_GET_REPEAT: { return (int)var_GetBool(pl_Get(p_intf->p_libvlc), "repeat"); } case IPC_SET_REPEAT: { return (int)var_SetBool(pl_Get(p_intf->p_libvlc), "repeat", (bool)wParam); } case IPC_SET_RATING: { // VLC does not support ratings so send back 0. PostMessage(p_sys->cad_window, WM_USER, 0, IPC_RATING_CHANGED_NOTIFICATION); return 0; } case IPC_SET_CALLBACK_HWND: { p_sys->cad_window = (HWND)wParam; return 1; } case IPC_SHOW_WINDOW: { // TODO. return 0; } case IPC_GET_STATE: { const int status = playlist_Status(pl_Get(p_intf->p_libvlc)); return status == PLAYLIST_RUNNING ? 1 : status == PLAYLIST_PAUSED ? 2 : 0; } case IPC_SHUTDOWN_NOTIFICATION: { p_sys->cad_window = NULL; return 1; } case IPC_CLOSE: { libvlc_Quit(p_intf->p_libvlc); return 1; } case IPC_GET_CURRENT_TRACK: { if (!p_sys->p_input) return 0; input_item_t* p_item = input_GetItem(p_sys->p_input); char buffer[DATA_MAX_LENGTH]; int buffer_len = 0; // If the i sstarts with file://, we assume that it is a local file and detailed // metadata is available. Otherwise, we assume it to be a network stream (i.e. radio) // with limited info (only a title). char* const file = decode_URI(input_item_GetURI(p_item)); if (strncmp(file, "file://", 7) == 0) { char* const title = input_item_GetTitleFbName(p_item); char* const artist = input_item_GetArtist(p_item); char* const album = input_item_GetAlbum(p_item); char* const cover = decode_URI(input_item_GetArtworkURL(p_item)); const unsigned int duration = input_item_GetDuration(p_item) / 1000000U; buffer_len = _snprintf( buffer, ARRAYSIZE(buffer), "%s\t%s\t%s\t\t\t\t\t%u\t%s\t\t%s\t\t\t\t\t\t\t", title ? title : "", artist ? artist : "", album ? album : "", duration, file ? &file[8] : "", cover ? &cover[8] : ""); // Skip the "file://" part. free(title); free(artist); free(album); free(cover); } else if (char* now_playing = input_item_GetNowPlaying(p_item)) { char* artist = NULL; char* title = now_playing; char* pos = strstr(now_playing, " - "); if (pos) { pos[0] = '\0'; artist = title; title = pos + 3; // Skip the " - " } buffer_len = _snprintf( buffer, ARRAYSIZE(buffer), "%s\t%s\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", title ? title : "", artist ? artist : ""); free(now_playing); } free(file); if (buffer_len) { wchar_t buffer_w[DATA_MAX_LENGTH]; const int buffer_w_len = MultiByteToWideChar( CP_UTF8, 0, buffer, buffer_len + 1, buffer_w, ARRAYSIZE(buffer_w)); COPYDATASTRUCT cds; cds.dwData = IPC_CURRENT_TRACK_NOTIFICATION; cds.lpData = &buffer_w; cds.cbData = buffer_w_len * sizeof(buffer_w[0]); SendMessage( p_sys->cad_window, WM_COPYDATA, IPC_CURRENT_TRACK_NOTIFICATION, (LPARAM)&cds); } return 1; } } return 0; }
//--------------------------------------------------------------------------- // Run: main loop //--------------------------------------------------------------------------- static void *Run( void * p_obj ) { int canc = vlc_savecancel(); intf_thread_t *p_intf = (intf_thread_t *)p_obj; bool b_error = false; char *skin_last = NULL; ThemeLoader *pLoader = NULL; OSLoop *loop = NULL; vlc_mutex_lock( &p_intf->p_sys->init_lock ); // Initialize singletons if( OSFactory::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize OSFactory" ); b_error = true; goto end; } if( AsyncQueue::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize AsyncQueue" ); b_error = true; goto end; } if( Interpreter::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate Interpreter" ); b_error = true; goto end; } if( VarManager::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate VarManager" ); b_error = true; goto end; } if( VlcProc::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize VLCProc" ); b_error = true; goto end; } if( VoutManager::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate VoutManager" ); b_error = true; goto end; } if( ThemeRepository::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate ThemeRepository" ); b_error = true; goto end; } if( Dialogs::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate qt4 dialogs provider" ); b_error = true; goto end; } // Load a theme skin_last = config_GetPsz( p_intf, "skins2-last" ); pLoader = new ThemeLoader( p_intf ); if( !skin_last || !pLoader->load( skin_last ) ) { // No skins (not even the default one). let's quit CmdQuit *pCmd = new CmdQuit( p_intf ); AsyncQueue *pQueue = AsyncQueue::instance( p_intf ); pQueue->push( CmdGenericPtr( pCmd ) ); msg_Err( p_intf, "no skins found : exiting"); } delete pLoader; free( skin_last ); // Get the instance of OSLoop loop = OSFactory::instance( p_intf )->getOSLoop(); // Signal the main thread this thread is now ready p_intf->p_sys->b_ready = true; vlc_cond_signal( &p_intf->p_sys->init_wait ); vlc_mutex_unlock( &p_intf->p_sys->init_lock ); // Enter the main event loop loop->run(); // Destroy OSLoop OSFactory::instance( p_intf )->destroyOSLoop(); // save and delete the theme if( p_intf->p_sys->p_theme ) { p_intf->p_sys->p_theme->saveConfig(); delete p_intf->p_sys->p_theme; p_intf->p_sys->p_theme = NULL; msg_Dbg( p_intf, "current theme deleted" ); } // save config file config_SaveConfigFile( p_intf, NULL ); end: // Destroy "singleton" objects Dialogs::destroy( p_intf ); ThemeRepository::destroy( p_intf ); VoutManager::destroy( p_intf ); VlcProc::destroy( p_intf ); VarManager::destroy( p_intf ); Interpreter::destroy( p_intf ); AsyncQueue::destroy( p_intf ); OSFactory::destroy( p_intf ); if( b_error ) { p_intf->p_sys->b_ready = true; vlc_cond_signal( &p_intf->p_sys->init_wait ); vlc_mutex_unlock( &p_intf->p_sys->init_lock ); libvlc_Quit( p_intf->p_libvlc ); } vlc_restorecancel(canc); return NULL; }
void X11Loop::handleX11Event() { XEvent event; OSFactory *pOsFactory = OSFactory::instance( getIntf() ); // Look for the next event in the queue XNextEvent( XDISPLAY, &event ); if( event.xany.window == m_rDisplay.getMainWindow() ) { if( event.type == ClientMessage ) { Atom wm_protocols = XInternAtom( XDISPLAY, "WM_PROTOCOLS", False); Atom wm_delete = XInternAtom( XDISPLAY, "WM_DELETE_WINDOW", False); if( event.xclient.message_type == wm_protocols && event.xclient.data.l[0] == wm_delete ) { msg_Dbg( getIntf(), "Received WM_DELETE_WINDOW message" ); libvlc_Quit( getIntf()->p_libvlc ); } } return; } // Find the window to which the event is sent GenericWindow *pWin = ((X11Factory*)pOsFactory)->m_windowMap[event.xany.window]; if( !pWin ) { return; } // Send the right event object to the window switch( event.type ) { case Expose: { EvtRefresh evt( getIntf(), event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height ); pWin->processEvent( evt ); break; } case FocusIn: { EvtFocus evt( getIntf(), true ); pWin->processEvent( evt ); break; } case FocusOut: { EvtFocus evt( getIntf(), false ); pWin->processEvent( evt ); break; } case MotionNotify: { // Don't trust the position in the event, it is // out of date. Get the actual current position instead int x, y; pOsFactory->getMousePos( x, y ); EvtMotion evt( getIntf(), x, y ); pWin->processEvent( evt ); break; } case LeaveNotify: { EvtLeave evt( getIntf() ); pWin->processEvent( evt ); break; } case ButtonPress: case ButtonRelease: { EvtMouse::ActionType_t action = EvtMouse::kDown; switch( event.type ) { case ButtonPress: action = EvtMouse::kDown; break; case ButtonRelease: action = EvtMouse::kUp; break; } int mod = X11ModToMod( event.xbutton.state ); // Check for double clicks if( event.type == ButtonPress && event.xbutton.button == 1 ) { mtime_t time = mdate(); int x, y; pOsFactory->getMousePos( x, y ); if( time - m_lastClickTime < m_dblClickDelay && x == m_lastClickPosX && y == m_lastClickPosY ) { m_lastClickTime = 0; action = EvtMouse::kDblClick; } else { m_lastClickTime = time; m_lastClickPosX = x; m_lastClickPosY = y; } } switch( event.xbutton.button ) { case 1: { EvtMouse evt( getIntf(), event.xbutton.x, event.xbutton.y, EvtMouse::kLeft, action, mod ); pWin->processEvent( evt ); break; } case 2: { EvtMouse evt( getIntf(), event.xbutton.x, event.xbutton.y, EvtMouse::kMiddle, action, mod ); pWin->processEvent( evt ); break; } case 3: { EvtMouse evt( getIntf(), event.xbutton.x, event.xbutton.y, EvtMouse::kRight, action, mod ); pWin->processEvent( evt ); break; } case 4: { // Scroll up EvtScroll evt( getIntf(), event.xbutton.x, event.xbutton.y, EvtScroll::kUp, mod ); pWin->processEvent( evt ); break; } case 5: { // Scroll down EvtScroll evt( getIntf(), event.xbutton.x, event.xbutton.y, EvtScroll::kDown, mod ); pWin->processEvent( evt ); break; } } break; } case KeyPress: case KeyRelease: { // Take the first keysym = lower case character, and translate. int key = keysymToVlcKey( XLookupKeysym( &event.xkey, 0 ) ); EvtKey evt( getIntf(), key, event.type==KeyRelease ? EvtKey::kUp : EvtKey::kDown, X11ModToMod( event.xkey.state ) ); pWin->processEvent( evt ); break; } case ClientMessage: { // Get the message type string type = XGetAtomName( XDISPLAY, event.xclient.message_type ); // Find the DnD object for this window X11DragDrop *pDnd = ((X11Factory*)pOsFactory)->m_dndMap[event.xany.window]; if( !pDnd ) { msg_Err( getIntf(), "no associated D&D object" ); return; } if( type == "XdndEnter" ) pDnd->dndEnter( event.xclient.data.l ); else if( type == "XdndPosition" ) pDnd->dndPosition( event.xclient.data.l ); else if( type == "XdndLeave" ) pDnd->dndLeave( event.xclient.data.l ); else if( type == "XdndDrop" ) pDnd->dndDrop( event.xclient.data.l ); break; } } }
LRESULT CALLBACK Win32Factory::Win32Proc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // Get pointer to thread info: should only work with the parent window intf_thread_t *p_intf = (intf_thread_t *)GetWindowLongPtr( hwnd, GWLP_USERDATA ); // If doesn't exist, treat windows message normally if( p_intf == NULL || p_intf->p_sys->p_osFactory == NULL ) { return DefWindowProc( hwnd, uMsg, wParam, lParam ); } Win32Factory *pFactory = (Win32Factory*)Win32Factory::instance( p_intf ); GenericWindow *pWin = pFactory->m_windowMap[hwnd]; if( hwnd == pFactory->getParentWindow() ) { if( uMsg == WM_SYSCOMMAND ) { // If closing parent window if( (wParam & 0xFFF0) == SC_CLOSE ) { libvlc_Quit( vlc_object_instance(p_intf) ); return 0; } else if( (wParam & 0xFFF0) == SC_MINIMIZE ) { pFactory->minimize(); return 0; } else if( (wParam & 0xFFF0) == SC_RESTORE ) { pFactory->restore(); return 0; } else { msg_Dbg( p_intf, "WM_SYSCOMMAND %i", (wParam & 0xFFF0) ); } } // Handle systray notifications else if( uMsg == MY_WM_TRAYACTION ) { if( (UINT)lParam == WM_LBUTTONDOWN ) { p_intf->p_sys->p_theme->getWindowManager().raiseAll(); CmdDlgHidePopupMenu aCmdPopup( p_intf ); aCmdPopup.execute(); return 0; } else if( (UINT)lParam == WM_RBUTTONDOWN ) { CmdDlgShowPopupMenu aCmdPopup( p_intf ); aCmdPopup.execute(); return 0; } else if( (UINT)lParam == WM_LBUTTONDBLCLK ) { CmdRestore aCmdRestore( p_intf ); aCmdRestore.execute(); return 0; } } } else if( pWin ) { Win32Loop* pLoop = (Win32Loop*) OSFactory::instance( p_intf )->getOSLoop(); if( pLoop ) return pLoop->processEvent( hwnd, uMsg, wParam, lParam ); } // If hwnd does not match any window or message not processed return DefWindowProc( hwnd, uMsg, wParam, lParam ); }
static void ProcessGesture( intf_thread_t *p_intf ) { intf_sys_t *p_sys = p_intf->p_sys; playlist_t *p_playlist = pl_Get( p_intf ); /* Do something */ /* If you modify this, please try to follow this convention: Start with LEFT, RIGHT for playback related commands and UP, DOWN, for other commands */ switch( p_sys->i_pattern ) { case LEFT: { msg_Dbg( p_intf, "Go backward in the movie!" ); input_thread_t *p_input = playlist_CurrentInput( p_playlist ); if( p_input == NULL ) break; int it = var_InheritInteger( p_intf , "short-jump-size" ); if( it > 0 ) var_SetTime( p_input, "time-offset", -CLOCK_FREQ * it ); vlc_object_release( p_input ); break; } case RIGHT: { msg_Dbg( p_intf, "Go forward in the movie!" ); input_thread_t *p_input = playlist_CurrentInput( p_playlist ); if( p_input == NULL ) break; int it = var_InheritInteger( p_intf , "short-jump-size" ); if( it > 0 ) var_SetTime( p_input, "time-offset", CLOCK_FREQ * it ); vlc_object_release( p_input ); break; } case GESTURE(LEFT,UP,NONE,NONE): msg_Dbg( p_intf, "Going slower." ); var_TriggerCallback( p_playlist, "rate-slower" ); break; case GESTURE(RIGHT,UP,NONE,NONE): msg_Dbg( p_intf, "Going faster." ); var_TriggerCallback( p_playlist, "rate-faster" ); break; case GESTURE(LEFT,RIGHT,NONE,NONE): case GESTURE(RIGHT,LEFT,NONE,NONE): { msg_Dbg( p_intf, "Play/Pause" ); input_thread_t *p_input = playlist_CurrentInput( p_playlist ); if( p_input == NULL ) break; int i_state = var_GetInteger( p_input, "state" ); i_state = (i_state == PLAYING_S) ? PAUSE_S : PLAYING_S; var_SetInteger( p_input, "state", i_state ); vlc_object_release( p_input ); break; } case GESTURE(LEFT,DOWN,NONE,NONE): playlist_Prev( p_playlist ); break; case GESTURE(RIGHT,DOWN,NONE,NONE): playlist_Next( p_playlist ); break; case UP: msg_Dbg(p_intf, "Louder"); playlist_VolumeUp( p_playlist, 1, NULL ); break; case DOWN: msg_Dbg(p_intf, "Quieter"); playlist_VolumeDown( p_playlist, 1, NULL ); break; case GESTURE(UP,DOWN,NONE,NONE): case GESTURE(DOWN,UP,NONE,NONE): msg_Dbg( p_intf, "Mute sound" ); playlist_MuteToggle( p_playlist ); break; case GESTURE(UP,RIGHT,NONE,NONE): { input_thread_t *p_input = playlist_CurrentInput( p_playlist ); if( p_input == NULL ) break; vlc_value_t list, list2; var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES, &list, &list2 ); if( list.p_list->i_count > 1 ) { int i_audio_es = var_GetInteger( p_input, "audio-es" ); int i; for( i = 0; i < list.p_list->i_count; i++ ) if( i_audio_es == list.p_list->p_values[i].i_int ) break; /* value of audio-es was not in choices list */ if( i == list.p_list->i_count ) { msg_Warn( p_input, "invalid current audio track, selecting 0" ); i = 0; } else if( i == list.p_list->i_count - 1 ) i = 1; else i++; var_SetInteger( p_input, "audio-es", list.p_list->p_values[i].i_int ); } var_FreeList( &list, &list2 ); vlc_object_release( p_input ); break; } case GESTURE(DOWN,RIGHT,NONE,NONE): { input_thread_t *p_input = playlist_CurrentInput( p_playlist ); if( p_input == NULL ) break; vlc_value_t list, list2; var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES, &list, &list2 ); if( list.p_list->i_count > 1 ) { int i_audio_es = var_GetInteger( p_input, "spu-es" ); int i; for( i = 0; i < list.p_list->i_count; i++ ) if( i_audio_es == list.p_list->p_values[i].i_int ) break; /* value of audio-es was not in choices list */ if( i == list.p_list->i_count ) { msg_Warn( p_input, "invalid current subtitle track, selecting 0" ); i = 0; } else if( i == list.p_list->i_count - 1 ) i = 1; else i++; var_SetInteger( p_input, "audio-es", list.p_list->p_values[i].i_int ); } var_FreeList( &list, &list2 ); vlc_object_release( p_input ); break; } case GESTURE(UP,LEFT,NONE,NONE): { bool val = var_ToggleBool( pl_Get( p_intf ), "fullscreen" ); if( p_sys->p_vout ) var_SetBool( p_sys->p_vout, "fullscreen", val ); break; } case GESTURE(DOWN,LEFT,NONE,NONE): /* FIXME: Should close the vout!"*/ libvlc_Quit( p_intf->p_libvlc ); break; case GESTURE(DOWN,LEFT,UP,RIGHT): case GESTURE(UP,RIGHT,DOWN,LEFT): msg_Dbg( p_intf, "a square was drawn!" ); break; } p_sys->i_num_gestures = 0; p_sys->i_pattern = 0; }
//--------------------------------------------------------------------------- // Run: main loop //--------------------------------------------------------------------------- static void *Run( void * p_obj ) { int canc = vlc_savecancel(); intf_thread_t *p_intf = (intf_thread_t *)p_obj; bool b_error = false; char *skin_last = NULL; ThemeLoader *pLoader = NULL; OSLoop *loop = NULL; vlc_mutex_lock( &p_intf->p_sys->init_lock ); // Initialize singletons if( OSFactory::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize OSFactory" ); b_error = true; goto end; } if( AsyncQueue::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize AsyncQueue" ); b_error = true; goto end; } if( Interpreter::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate Interpreter" ); b_error = true; goto end; } if( VarManager::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate VarManager" ); b_error = true; goto end; } if( VlcProc::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot initialize VLCProc" ); b_error = true; goto end; } if( VoutManager::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate VoutManager" ); b_error = true; goto end; } if( ThemeRepository::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate ThemeRepository" ); b_error = true; goto end; } if( Dialogs::instance( p_intf ) == NULL ) { msg_Err( p_intf, "cannot instanciate qt4 dialogs provider" ); b_error = true; goto end; } // Load a theme skin_last = config_GetPsz( p_intf, "skins2-last" ); pLoader = new ThemeLoader( p_intf ); if( !skin_last || !*skin_last || !pLoader->load( skin_last ) ) { // Get the resource path and try to load the default skin OSFactory *pOSFactory = OSFactory::instance( p_intf ); const list<string> &resPath = pOSFactory->getResourcePath(); const string &sep = pOSFactory->getDirSeparator(); list<string>::const_iterator it; for( it = resPath.begin(); it != resPath.end(); it++ ) { string path = (*it) + sep + "default.vlt"; if( pLoader->load( path ) ) { // Theme loaded successfully break; } } if( it == resPath.end() ) { // Last chance: the user can select a new theme file if( Dialogs::instance( p_intf ) ) { CmdDlgChangeSkin *pCmd = new CmdDlgChangeSkin( p_intf ); AsyncQueue *pQueue = AsyncQueue::instance( p_intf ); pQueue->push( CmdGenericPtr( pCmd ) ); } else { // No dialogs provider, just quit... CmdQuit *pCmd = new CmdQuit( p_intf ); AsyncQueue *pQueue = AsyncQueue::instance( p_intf ); pQueue->push( CmdGenericPtr( pCmd ) ); msg_Err( p_intf, "cannot show the \"open skin\" dialog: exiting..."); } } } delete pLoader; free( skin_last ); // Get the instance of OSLoop loop = OSFactory::instance( p_intf )->getOSLoop(); // Signal the main thread this thread is now ready p_intf->p_sys->b_ready = true; vlc_cond_signal( &p_intf->p_sys->init_wait ); vlc_mutex_unlock( &p_intf->p_sys->init_lock ); // Enter the main event loop loop->run(); // Destroy OSLoop OSFactory::instance( p_intf )->destroyOSLoop(); // save and delete the theme if( p_intf->p_sys->p_theme ) { p_intf->p_sys->p_theme->saveConfig(); delete p_intf->p_sys->p_theme; p_intf->p_sys->p_theme = NULL; msg_Dbg( p_intf, "current theme deleted" ); } // save config file config_SaveConfigFile( p_intf, NULL ); end: // Destroy "singleton" objects Dialogs::destroy( p_intf ); ThemeRepository::destroy( p_intf ); VoutManager::destroy( p_intf ); VlcProc::destroy( p_intf ); VarManager::destroy( p_intf ); Interpreter::destroy( p_intf ); AsyncQueue::destroy( p_intf ); OSFactory::destroy( p_intf ); if( b_error ) { p_intf->p_sys->b_ready = true; vlc_cond_signal( &p_intf->p_sys->init_wait ); vlc_mutex_unlock( &p_intf->p_sys->init_lock ); libvlc_Quit( p_intf->p_libvlc ); } vlc_restorecancel(canc); return NULL; }
/***************************************************************************** * OpenDemux: initialize the target, ie. parse the command *****************************************************************************/ static int OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; char * psz_name = p_demux->psz_location; p_demux->p_sys = NULL; /* Check for a "vlc://nop" command */ if( !strcasecmp( psz_name, "nop" ) ) { nop: msg_Info( p_demux, "command `nop'" ); p_demux->pf_demux = DemuxNoOp; p_demux->pf_control = DemuxControl; return VLC_SUCCESS; } /* Check for a "vlc://quit" command */ if( !strcasecmp( psz_name, "quit" ) ) { msg_Info( p_demux, "command `quit'" ); p_demux->pf_demux = DemuxNoOp; p_demux->pf_control = DemuxControl; libvlc_Quit( p_demux->p_libvlc ); return VLC_SUCCESS; } if( !strcasecmp( psz_name, "pause" ) ) { msg_Info( p_demux, "command `pause'" ); p_demux->pf_demux = DemuxHold; p_demux->pf_control = DemuxControl; return VLC_SUCCESS; } /* Check for a "vlc://pause:***" command */ if( !strncasecmp( psz_name, "pause:", 6 ) ) { double f = us_atof( psz_name + 6 ); mtime_t length = f * CLOCK_FREQ; msg_Info( p_demux, "command `pause %f'", f ); if( length == 0 ) goto nop; /* avoid division by zero */ demux_sys_t *p_sys = malloc( sizeof( *p_sys ) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->end = mdate() + length; p_sys->length = length; p_demux->p_sys = p_sys; p_demux->pf_demux = DemuxPause; p_demux->pf_control = ControlPause; return VLC_SUCCESS; } msg_Err( p_demux, "unknown command `%s'", psz_name ); return VLC_EGENERIC; }
/***************************************************************************** * RunIntf: main loop *****************************************************************************/ static void RunIntf( intf_thread_t *p_intf ) { intf_sys_t *p_sys = p_intf->p_sys; int canc = vlc_savecancel(); input_thread_t *p_input; /* Main loop */ while( vlc_object_alive( p_intf ) ) { vlc_mutex_lock( &p_sys->lock ); /* * mouse cursor */ if( p_sys->b_got_gesture ) { int i_interval = 0; /* Do something */ /* If you modify this, please try to follow this convention: Start with LEFT, RIGHT for playback related commands and UP, DOWN, for other commands */ playlist_t * p_playlist = pl_Get( p_intf ); switch( p_sys->i_pattern ) { case LEFT: msg_Dbg( p_intf, "Go backward in the movie!" ); p_input = playlist_CurrentInput( p_playlist ); if( p_input ) { i_interval = var_InheritInteger( p_intf , "short-jump-size" ); if ( i_interval > 0 ) { mtime_t i_time = ( (mtime_t)( -i_interval ) * 1000000L); var_SetTime( p_input, "time-offset", i_time ); } vlc_object_release( p_input ); } break; case RIGHT: msg_Dbg( p_intf, "Go forward in the movie!" ); p_input = playlist_CurrentInput( p_playlist ); if( p_input ) { i_interval = var_InheritInteger( p_intf , "short-jump-size" ); if ( i_interval > 0 ) { mtime_t i_time = ( (mtime_t)( i_interval ) * 1000000L); var_SetTime( p_input, "time-offset", i_time ); } vlc_object_release( p_input ); } break; case GESTURE(LEFT,UP,NONE,NONE): msg_Dbg( p_intf, "Going slower." ); p_input = playlist_CurrentInput( p_playlist ); if( p_input ) { var_TriggerCallback( p_input, "rate-slower" ); vlc_object_release( p_input ); } break; case GESTURE(RIGHT,UP,NONE,NONE): msg_Dbg( p_intf, "Going faster." ); p_input = playlist_CurrentInput( p_playlist ); if( p_input ) { var_TriggerCallback( p_input, "rate-faster" ); vlc_object_release( p_input ); } break; case GESTURE(LEFT,RIGHT,NONE,NONE): case GESTURE(RIGHT,LEFT,NONE,NONE): msg_Dbg( p_intf, "Play/Pause" ); p_input = playlist_CurrentInput( p_playlist ); if( p_input ) { int i_state = var_GetInteger( p_input, "state" ); var_SetInteger( p_input, "state", ( i_state != PLAYING_S ) ? PLAYING_S : PAUSE_S ); vlc_object_release( p_input ); } break; case GESTURE(LEFT,DOWN,NONE,NONE): playlist_Prev( p_playlist ); break; case GESTURE(RIGHT,DOWN,NONE,NONE): playlist_Next( p_playlist ); break; case UP: msg_Dbg(p_intf, "Louder"); aout_VolumeUp( p_playlist, 1, NULL ); break; case DOWN: msg_Dbg(p_intf, "Quieter"); aout_VolumeDown( p_playlist, 1, NULL ); break; case GESTURE(UP,DOWN,NONE,NONE): case GESTURE(DOWN,UP,NONE,NONE): msg_Dbg( p_intf, "Mute sound" ); aout_ToggleMute( p_playlist, NULL ); break; case GESTURE(UP,RIGHT,NONE,NONE): { vlc_value_t list, list2; int i_count, i, i_audio_es; p_input = playlist_CurrentInput( p_playlist ); if( !p_input ) break; i_audio_es = var_GetInteger( p_input, "audio-es" ); var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES, &list, &list2 ); i_count = list.p_list->i_count; if( i_count <= 1 ) { var_FreeList( &list, &list2 ); vlc_object_release( p_input ); break; } for( i = 0; i < i_count; i++ ) { if( i_audio_es == list.p_list->p_values[i].i_int ) break; } /* value of audio-es was not in choices list */ if( i == i_count ) { msg_Warn( p_input, "invalid current audio track, selecting 0" ); i = 0; } else if( i == i_count - 1 ) i = 1; else i++; var_SetInteger( p_input, "audio-es", list.p_list->p_values[i].i_int ); var_FreeList( &list, &list2 ); vlc_object_release( p_input ); } break; case GESTURE(DOWN,RIGHT,NONE,NONE): { vlc_value_t list, list2; int i_count, i, i_spu_es; p_input = playlist_CurrentInput( p_playlist ); if( !p_input ) break; i_spu_es = var_GetInteger( p_input, "spu-es" ); var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES, &list, &list2 ); i_count = list.p_list->i_count; if( i_count <= 1 ) { vlc_object_release( p_input ); var_FreeList( &list, &list2 ); break; } for( i = 0; i < i_count; i++ ) { if( i_spu_es == list.p_list->p_values[i].i_int ) { break; } } /* value of spu-es was not in choices list */ if( i == i_count ) { msg_Warn( p_input, "invalid current subtitle track, selecting 0" ); i = 0; } else if( i == i_count - 1 ) i = 0; else i++; var_SetInteger( p_input, "spu-es", list.p_list->p_values[i].i_int); var_FreeList( &list, &list2 ); vlc_object_release( p_input ); } break; case GESTURE(UP,LEFT,NONE,NONE): { bool val = var_ToggleBool( pl_Get( p_intf ), "fullscreen" ); if( p_sys->p_vout ) var_SetBool( p_sys->p_vout, "fullscreen", val ); break; } case GESTURE(DOWN,LEFT,NONE,NONE): /* FIXME: Should close the vout!"*/ libvlc_Quit( p_intf->p_libvlc ); break; case GESTURE(DOWN,LEFT,UP,RIGHT): case GESTURE(UP,RIGHT,DOWN,LEFT): msg_Dbg( p_intf, "a square was drawn!" ); break; default: break; } p_sys->i_num_gestures = 0; p_sys->i_pattern = 0; p_sys->b_got_gesture = false; } /* * video output */ if( p_sys->p_vout && !vlc_object_alive( p_sys->p_vout ) ) { var_DelCallback( p_sys->p_vout, "mouse-moved", MouseEvent, p_intf ); var_DelCallback( p_sys->p_vout, "mouse-button-down", MouseEvent, p_intf ); vlc_object_release( p_sys->p_vout ); p_sys->p_vout = NULL; } if( p_sys->p_vout == NULL ) { p_input = playlist_CurrentInput( pl_Get( p_intf ) ); if( p_input ) { p_sys->p_vout = input_GetVout( p_input ); vlc_object_release( p_input ); } if( p_sys->p_vout ) { var_AddCallback( p_sys->p_vout, "mouse-moved", MouseEvent, p_intf ); var_AddCallback( p_sys->p_vout, "mouse-button-down", MouseEvent, p_intf ); } } vlc_mutex_unlock( &p_sys->lock ); /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); } vlc_restorecancel( canc ); }