Beispiel #1
0
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;
}
Beispiel #2
0
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 ();
}
Beispiel #3
0
/*****************************************************************************
 * 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 );
}
Beispiel #5
0
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 );
    }
}
Beispiel #6
0
/**
 * 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
}
Beispiel #7
0
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 );
}
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
0
/*****************************************************************************
 * 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 );
}
Beispiel #11
0
/*****************************************************************************
 * 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;
}
Beispiel #12
0
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 );
}
Beispiel #14
0
/**
 * 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 );
}
Beispiel #15
0
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;
}
Beispiel #16
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;
}
Beispiel #17
0
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;
        }
    }
}
Beispiel #18
0
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 );
}
Beispiel #19
0
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;
}
Beispiel #20
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;
}
Beispiel #21
0
/*****************************************************************************
 * 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;
}
Beispiel #22
0
/*****************************************************************************
 * 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 );
}