2017-03-25 09:47:51 +00:00
/ *
* MiracleCast - Wifi - Display / Miracast Implementation
*
* Copyright ( c ) 2013 - 2014 David Herrmann < dh . herrmann @ gmail . com >
*
* MiracleCast is free software ; you can redistribute it and / or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* MiracleCast is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with MiracleCast ; If not , see < http : //www.gnu.org/licenses/>.
* /
2017-03-22 03:12:43 +00:00
using Org.Freedesktop.NetworkManager ;
using Org.Freedesktop.Miracle.Wifi ;
using Org.Freedesktop.Miracle.Wfd ;
const string BUS_NAME_NETWORK_MANAGER = " org.freedesktop.NetworkManager " ;
const string BUS_NAME_WIFID = " org.freedesktop.miracle.wifi " ;
const string BUS_NAME_DISPD = " org.freedesktop.miracle.wfd " ;
const string OBJ_PATH_DEVICE = " /org/freedesktop/NetworkManager/Devices " ;
const string OBJ_PATH_LINK = " /org/freedesktop/miracle/wifi/link " ;
const string OBJ_PATH_PEER = " /org/freedesktop/miracle/wifi/peer " ;
const string OBJ_PATH_SINK = " /org/freedesktop/miracle/wfd/sink " ;
const string OBJ_PATH_SESSION = " /org/freedesktop/miracle/wfd/session " ;
2017-03-22 14:43:35 +00:00
const string IFACE_DEVICE = " org.freedesktop.NetworkManager.Device " ;
const string IFACE_LINK = " org.freedesktop.miracle.wifi.Link " ;
const string IFACE_PEER = " org.freedesktop.miracle.wifi.Peer " ;
const string IFACE_SINK = " org.freedesktop.miracle.wfd.Sink " ;
const string IFACE_SESSION = " org.freedesktop.miracle.wfd.Session " ;
2017-03-22 03:12:43 +00:00
errordomain WfdCtlError
{
NO_SUCH_NIC ,
2017-03-22 14:43:35 +00:00
TIMEOUT ,
MONITOR_GONE ,
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private void print ( string format , . . . )
2017-03-22 03:12:43 +00:00
{
var argv = va_list ( ) ;
stderr . printf ( " %s: " , Environment . get_prgname ( ) ) ;
stderr . vprintf ( format , argv ) ;
stderr . printf ( " \n " ) ;
}
// to deal with sd_bus_path_encode/decode()ed path
2017-03-22 14:43:35 +00:00
private string decode_path ( string s )
2017-03-22 03:12:43 +00:00
{
char c ;
StringBuilder d = new StringBuilder ( ) ;
for ( var i = 0 ; i < s . length ; i + + ) {
if ( s . data [ i ] = = ( uint8 ) '_' ) {
c = ( char ) s . substring ( i + 1 , 2 ) . to_long ( null , 16 ) ;
i + = 2 ;
}
else {
c = ( char ) s . data [ i ] ;
}
d . append_c ( c ) ;
}
return d . str ;
}
2017-03-22 14:43:35 +00:00
private class WfdCtl : GLib . Application
2017-03-22 03:12:43 +00:00
{
2017-03-22 14:43:35 +00:00
static string opt_iface ;
static string opt_wfd_subelems ;
static string opt_peer_mac ;
static string opt_display ;
static string opt_authority ;
static int opt_monitor_num ;
static string opt_audio_device ;
protected signal void link_added ( string index , Link link ) ;
protected signal void link_removed ( string index , Link link ) ;
protected signal void peer_added ( string label , Peer peer ) ;
protected signal void peer_removed ( string label , Peer peer ) ;
protected signal void sink_added ( string label , Sink sink ) ;
protected signal void sink_removed ( string label , Sink sink ) ;
protected signal void session_added ( string id , Session session ) ;
protected signal void session_removed ( string id , Session session ) ;
DBusObjectManagerClient nm ;
DBusObjectManagerClient wifi ;
DBusObjectManagerClient wfd ;
HashTable < string , Device > devices ;
HashTable < string , Link > links ;
HashTable < string , Peer > peers ;
HashTable < string , Sink > sinks ;
HashTable < string , Session > sessions ;
string curr_sink_mac ;
Gdk . Display display ;
2017-03-25 07:36:13 +00:00
Session curr_session ;
2017-03-22 14:43:35 +00:00
const GLib . OptionEntry [ ] option_entries = {
{ " interface " , 'i' , 0 , OptionArg . STRING , ref opt_iface , " name of wireless network interface " , " WNIC name " } ,
{ " wfd-subelems " , 'w' , 0 , OptionArg . STRING , ref opt_wfd_subelems , " device infomation. default: 000600111c4400c8 " , " device info subelems " } ,
{ " peer-mac " , 'p' , 0 , OptionArg . STRING , ref opt_peer_mac , " MAC address of target peer " , " peer MAC " } ,
{ " authority " , 'x' , 0 , OptionArg . STRING , ref opt_authority , " authority to capture from display. default: XAUTHORITY environment variable " , " display authority " } ,
2017-03-25 09:47:51 +00:00
{ " display " , 'd' , 0 , OptionArg . STRING , ref opt_display , " display name. default: DISPLAY environment variable " , " display name " } ,
2017-03-22 14:43:35 +00:00
{ " monitor-num " , 'm' , 0 , OptionArg . INT , ref opt_monitor_num , " monitor number. default: -1, primary monitor " , " monitor number " } ,
{ " audio-device " , 'a' , 0 , OptionArg . STRING , ref opt_audio_device , " pulseaudio device name " , " audio device name " } ,
{ null } ,
} ;
public WfdCtl ( )
{
Object ( application_id : " org.freedesktop.miracle.WfdCtl " ,
flags : ApplicationFlags . FLAGS_NONE ) ;
devices = new HashTable < string , Device > ( str_hash , str_equal ) ;
links = new HashTable < string , Link > ( str_hash , str_equal ) ;
peers = new HashTable < string , Peer > ( str_hash , str_equal ) ;
sinks = new HashTable < string , Sink > ( str_hash , str_equal ) ;
sessions = new HashTable < string , Session > ( str_hash , str_equal ) ;
add_main_option_entries ( option_entries ) ;
}
2017-03-25 07:36:13 +00:00
private DBusProxy ? add_object ( string path ) throws Error
2017-03-22 14:43:35 +00:00
{
int sep = path . last_index_of_char ( '/' ) ;
string prefix = path . substring ( 0 , sep ) ;
string key = path . substring ( sep + 1 ) ;
switch ( prefix ) {
case OBJ_PATH_DEVICE :
Device d = Bus . get_proxy_sync ( BusType . SYSTEM ,
BUS_NAME_NETWORK_MANAGER ,
path ) ;
2017-03-25 07:36:13 +00:00
if ( is_wnic ( d . interface ) & & ! devices . contains ( d . interface ) ) {
2017-03-22 14:43:35 +00:00
devices . insert ( d . interface , d ) ;
2017-03-25 07:36:13 +00:00
return d as DBusProxy ;
2017-03-22 14:43:35 +00:00
}
break ;
case OBJ_PATH_LINK :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Link l = links . lookup ( key ) ;
if ( null = = l ) {
l = Bus . get_proxy_sync ( BusType . SYSTEM ,
BUS_NAME_WIFID ,
path ) ;
links . insert ( key , l ) ;
info ( " found wireless interface: %s \n " , l . interface_name ) ;
link_added ( key , l ) ;
}
return l as DBusProxy ;
2017-03-22 14:43:35 +00:00
case OBJ_PATH_PEER :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Peer p = peers . lookup ( key ) ;
if ( null = = p ) {
p = Bus . get_proxy_sync ( BusType . SYSTEM ,
BUS_NAME_WIFID ,
path ) ;
peers . insert ( key , p ) ;
info ( " peer added: %s \n " , key ) ;
peer_added ( key , p ) ;
2017-03-22 14:43:35 +00:00
}
2017-03-25 07:36:13 +00:00
return p as DBusProxy ;
2017-03-22 14:43:35 +00:00
case OBJ_PATH_SINK :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Sink s = sinks . lookup ( key ) ;
if ( null = = s ) {
s = Bus . get_proxy_sync ( BusType . SYSTEM ,
BUS_NAME_DISPD ,
path ) ;
sinks . insert ( key , s ) ;
info ( " sink added: %s " , key ) ;
sink_added ( key , s ) ;
}
return s as DBusProxy ;
2017-03-22 14:43:35 +00:00
case OBJ_PATH_SESSION :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Session s = sessions . lookup ( key ) ;
if ( null = = s ) {
s = Bus . get_proxy_sync ( BusType . SYSTEM ,
BUS_NAME_DISPD ,
path ) ;
sessions . insert ( key , s ) ;
info ( " session added: %s " , key ) ;
session_added ( key , s ) ;
}
return s as DBusProxy ;
2017-03-22 03:12:43 +00:00
}
2017-03-25 07:36:13 +00:00
return null ;
2017-03-22 14:43:35 +00:00
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
private void remove_object ( string path )
{
int sep = path . last_index_of_char ( '/' ) ;
string prefix = path . substring ( 0 , sep ) ;
string key = path . substring ( sep + 1 ) ;
switch ( prefix ) {
case OBJ_PATH_DEVICE :
2017-03-25 07:36:13 +00:00
devices . remove ( key ) ;
2017-03-22 03:12:43 +00:00
break ;
2017-03-22 14:43:35 +00:00
case OBJ_PATH_LINK :
2017-03-25 07:36:13 +00:00
key = decode_path ( key ) ;
Link l = links . lookup ( key ) ;
if ( null = = l ) {
break ;
}
links . remove ( key ) ;
link_removed ( key , l ) ;
2017-03-22 14:43:35 +00:00
break ;
case OBJ_PATH_PEER :
2017-03-25 07:36:13 +00:00
key = decode_path ( key ) ;
Peer p = peers . lookup ( key ) ;
if ( null = = p ) {
break ;
}
peers . remove ( key ) ;
peer_removed ( key , p ) ;
2017-03-22 14:43:35 +00:00
break ;
case OBJ_PATH_SINK :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Sink s = sinks . lookup ( key ) ;
if ( null = = s ) {
break ;
}
sinks . remove ( key ) ;
sink_removed ( key , s ) ;
2017-03-22 14:43:35 +00:00
break ;
case OBJ_PATH_SESSION :
key = decode_path ( key ) ;
2017-03-25 07:36:13 +00:00
Session s = sessions . lookup ( key ) ;
if ( null = = s ) {
break ;
}
sessions . remove ( key ) ;
session_removed ( key , s ) ;
2017-03-22 14:43:35 +00:00
break ;
}
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private void on_object_added ( DBusObjectManager m , DBusObject o )
{
try {
add_object ( o . get_object_path ( ) ) ;
}
catch ( Error e ) {
print ( " failed to fetch information from DBus for object: %s " ,
o . get_object_path ( ) ) ;
}
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private void on_object_removed ( DBusObjectManager m , DBusObject o )
{
remove_object ( o . get_object_path ( ) ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private void fetch_info_from_dbus ( ) throws Error
{
wifi = new DBusObjectManagerClient . for_bus_sync (
BusType . SYSTEM ,
DBusObjectManagerClientFlags . NONE ,
BUS_NAME_WIFID ,
" /org/freedesktop/miracle/wifi " ,
null ,
null ) ;
wifi . object_added . connect ( on_object_added ) ;
wifi . object_removed . connect ( on_object_removed ) ;
nm = new DBusObjectManagerClient . for_bus_sync (
BusType . SYSTEM ,
DBusObjectManagerClientFlags . NONE ,
BUS_NAME_NETWORK_MANAGER ,
" /org/freedesktop " ,
null ,
null ) ;
nm . object_added . connect ( on_object_added ) ;
nm . object_removed . connect ( on_object_removed ) ;
wfd = new DBusObjectManagerClient . for_bus_sync (
BusType . SYSTEM ,
DBusObjectManagerClientFlags . NONE ,
BUS_NAME_DISPD ,
" /org/freedesktop/miracle/wfd " ,
null ,
null ) ;
wfd . object_added . connect ( on_object_added ) ;
wfd . object_removed . connect ( on_object_removed ) ;
foreach ( var o in wifi . get_objects ( ) ) {
add_object ( o . get_object_path ( ) ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
foreach ( var o in nm . get_objects ( ) ) {
add_object ( o . get_object_path ( ) ) ;
}
foreach ( var o in wfd . get_objects ( ) ) {
add_object ( o . get_object_path ( ) ) ;
}
2017-03-22 03:12:43 +00:00
}
2017-03-25 07:36:13 +00:00
private async void acquire_wnic_ownership ( ) throws Error
2017-03-22 14:43:35 +00:00
{
Device d = find_device_by_name ( opt_iface ) ;
2017-03-25 07:36:13 +00:00
if ( null ! = d & & d . managed ) {
info ( " NetworkManager is releasing ownership of %s... " , opt_iface ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
d . managed = false ;
yield wait_prop_changed ( d as DBusProxy , " Managed " ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
Link l = find_link_by_name ( opt_iface ) ;
if ( null = = l ) {
throw new WfdCtlError . NO_SUCH_NIC ( " no such wireless adapter: %s " ,
opt_iface ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
if ( ! l . managed ) {
2017-03-25 07:36:13 +00:00
info ( " wifid is acquiring ownership of %s... " , opt_iface ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
l . manage ( ) ;
yield wait_prop_changed ( l as DBusProxy , " Managed " ) ;
}
2017-03-25 07:36:13 +00:00
}
2017-03-22 03:12:43 +00:00
2017-03-25 07:36:13 +00:00
private async void start_p2p_scan ( ) throws Error
{
Link l = find_link_by_name ( opt_iface ) ;
2017-03-22 14:43:35 +00:00
if ( l . wfd_subelements ! = opt_wfd_subelems ) {
info ( " update wfd_subelems to broadcast what kind of device we are " ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
l . wfd_subelements = opt_wfd_subelems ;
yield wait_prop_changed ( l as DBusProxy , " WfdSubelements " ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
if ( ! l . p2_p_scanning ) {
info ( " start P2P scanning... " ) ;
l . p2_p_scanning = true ;
yield wait_prop_changed ( l as DBusProxy , " P2PScanning " ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
print ( " wait for peer '%s'... " , opt_peer_mac ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
private async void wait_for_target_sink ( )
{
if ( null ! = find_sink_by_mac ( opt_peer_mac ) ) {
return ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
ulong id = sink_added . connect ( ( l , s ) = > {
if ( null ! = find_sink_by_mac ( opt_peer_mac ) ) {
wait_for_target_sink . callback ( ) ;
}
} ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
yield ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
disconnect ( id ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private async void form_p2p_group ( ) throws Error
{
if ( null ! = curr_sink_mac ) {
print ( " already hang out with sink: %s " , curr_sink_mac ) ;
return ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
Sink s = find_sink_by_mac ( opt_peer_mac ) ;
curr_sink_mac = opt_peer_mac ;
string l = s . peer ;
l = decode_path ( l . substring ( l . last_index_of_char ( '/' ) + 1 ) ) ;
Peer p = peers . lookup ( l ) ;
info ( " forming P2P group with %s (%s)... " , p . p2_p_mac , p . friendly_name ) ;
p . connect ( " auto " , " " ) ;
yield wait_prop_changed ( p as DBusProxy , " Connected " , 20 ) ;
info ( " P2P group formed " ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-23 17:08:18 +00:00
# if GDK_VERSION_NEWER_THEN_3_22 & & VALA_VERSION_NEWER_THEN_0_34
2017-03-23 15:13:24 +00:00
private void get_monitor_geometry ( out Gdk . Rectangle g ) throws Error
2017-03-22 14:43:35 +00:00
{
2017-03-23 15:13:24 +00:00
Gdk . Monitor m ;
if ( - 1 = = opt_monitor_num ) {
m = display . get_primary_monitor ( ) ;
}
else {
m = display . get_monitor ( opt_monitor_num ) ;
}
2017-03-22 14:43:35 +00:00
if ( null = = m ) {
2017-03-23 15:13:24 +00:00
throw new WfdCtlError . MONITOR_GONE ( " specified monitor disappeared " ) ;
2017-03-22 14:43:35 +00:00
}
2017-03-23 15:13:24 +00:00
g = m . geometry ;
}
# else
private void get_monitor_geometry ( out Gdk . Rectangle g ) throws Error
{
var s = display . get_default_screen ( ) ;
int m = ( - 1 = = opt_monitor_num )
? s . get_primary_monitor ( )
: opt_monitor_num ;
if ( s . get_n_monitors ( ) < = m ) {
throw new WfdCtlError . MONITOR_GONE ( " specified monitor disappeared " ) ;
}
s . get_monitor_geometry ( m , out g ) ;
}
# endif
2017-03-25 07:36:13 +00:00
private unowned string session_state_to_str ( int s )
{
switch ( s ) {
case 1 :
return " connecting " ;
case 2 :
return " capabilities exchanging " ;
case 3 :
return " established " ;
case 4 :
return " seting up session parameters " ;
case 5 :
return " paused " ;
case 6 :
return " playing " ;
case 7 :
return " tearing down " ;
}
return " unknown " ;
}
2017-03-23 15:13:24 +00:00
private async void establish_session ( ) throws Error
{
Gdk . Rectangle g ;
get_monitor_geometry ( out g ) ;
2017-03-22 14:43:35 +00:00
info ( " establishing display session... " ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
Sink sink = find_sink_by_mac ( opt_peer_mac ) ;
2017-03-25 07:36:13 +00:00
string path = sink . start_session ( opt_authority ,
2017-03-22 14:43:35 +00:00
@" x://$(opt_display) " ,
2017-03-23 15:13:24 +00:00
g . x ,
g . y ,
g . width ,
g . height ,
2017-03-22 14:43:35 +00:00
null = = opt_audio_device ? " " : opt_audio_device ) ;
2017-03-25 07:36:13 +00:00
curr_session = add_object ( path ) as Session ;
( curr_session as DBusProxy ) . g_properties_changed . connect ( ( props ) = > {
string k ;
Variant v ;
foreach ( var prop in props ) {
prop . get ( " {sv} " , out k , out v ) ;
if ( k ! = " State " ) {
continue ;
}
info ( " session status: %s " , session_state_to_str ( v . get_int32 ( ) ) ) ;
}
} ) ;
info ( " session status: %s " , session_state_to_str ( curr_session . state ) ) ;
}
private async void wait_for_session_ending ( )
{
info ( " wait for session ending " ) ;
session_removed . connect ( ( id , s ) = > {
info ( " session ended " ) ;
curr_session = null ;
wait_for_session_ending . callback ( ) ;
} ) ;
yield ;
}
private async void release_wnic_ownership ( ) throws Error
{
Link l = find_link_by_name ( opt_iface ) ;
if ( null = = l ) {
throw new WfdCtlError . NO_SUCH_NIC ( " no such wireless adapter: %s " ,
opt_iface ) ;
}
if ( l . managed ) {
info ( " wifid is releasing ownership of %s... " , opt_iface ) ;
l . unmanage ( ) ;
yield wait_prop_changed ( l as DBusProxy , " Managed " ) ;
}
Device d = find_device_by_name ( opt_iface ) ;
if ( null ! = d & & ! d . managed ) {
info ( " NetworkManager is acquiring ownership of %s... " , opt_iface ) ;
d . managed = true ;
yield wait_prop_changed ( d as DBusProxy , " Managed " ) ;
}
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private async void start_wireless_display ( ) throws Error
{
fetch_info_from_dbus ( ) ;
2017-03-25 07:36:13 +00:00
yield acquire_wnic_ownership ( ) ;
2017-03-22 14:43:35 +00:00
yield start_p2p_scan ( ) ;
yield wait_for_target_sink ( ) ;
yield form_p2p_group ( ) ;
yield establish_session ( ) ;
2017-03-25 07:36:13 +00:00
yield wait_for_session_ending ( ) ;
yield release_wnic_ownership ( ) ;
2017-03-25 09:47:51 +00:00
quit ( ) ;
2017-03-25 07:36:13 +00:00
print ( " Bye " ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-25 09:47:51 +00:00
public void stop_wireless_display ( )
{
info ( " tearing down wireless display... " ) ;
try {
if ( null ! = curr_session ) {
curr_session . teardown ( ) ;
}
else {
release_wnic_ownership . begin ( ( ) = > {
quit ( ) ;
print ( " Bye " ) ;
} ) ;
}
}
catch ( Error e ) {
warning ( " %s " , e . message ) ;
}
}
2017-03-22 14:43:35 +00:00
private bool check_options ( )
{
if ( null = = opt_peer_mac ) {
print ( " please specify a peer MAC with -p option " ) ;
return false ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
if ( null = = opt_display ) {
opt_display = Environment . get_variable ( " DISPLAY " ) ;
if ( null = = opt_display ) {
print ( " no video source found. play specify one by DISPLAY " +
" environment or -d option " ) ;
return false ;
}
else {
print ( " no display name specified by -d, " +
" use DISPLAY environment variable instead " ) ;
}
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
if ( null = = opt_authority ) {
opt_authority = Environment . get_variable ( " XAUTHORITY " ) ;
if ( null = = opt_authority ) {
print ( " no display authority found. play specify one by XAUTHORITY " +
" environment or -x option " ) ;
return false ;
}
else {
print ( " no display authority specified by -x, " +
" use XAUTHORITY environment variable instead " ) ;
}
}
if ( null = = opt_iface ) {
opt_iface = " wlan0 " ;
print ( " no wireless adapter specified by -i, use '%s' instead " ,
opt_iface ) ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
if ( null = = opt_wfd_subelems ) {
opt_wfd_subelems = " 000600111c4400c8 " ;
print ( " no wfd_subelems specified by -w, use '%s' instead " ,
opt_wfd_subelems ) ;
}
display = Gdk . Display . open ( opt_display ) ;
if ( null = = display ) {
print ( " invalid display option: %s " , opt_display ) ;
return false ;
}
2017-03-23 15:13:24 +00:00
int n_monitors ;
2017-03-23 17:08:18 +00:00
# if GDK_VERSION_NEWER_THEN_3_22 & & VALA_VERSION_NEWER_THEN_0_34
2017-03-23 15:13:24 +00:00
n_monitors = display . get_n_monitors ( ) ;
# else
n_monitors = display . get_default_screen ( ) . get_n_monitors ( ) ;
# endif
if ( - 1 > opt_monitor_num | | opt_monitor_num > = n_monitors ) {
2017-03-22 14:43:35 +00:00
print ( " invalid screen number option: %d " , opt_monitor_num ) ;
return false ;
}
return true ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
protected override void activate ( )
{
if ( ! check_options ( ) ) {
return ;
}
start_wireless_display . begin ( ( o , r ) = > {
try {
start_wireless_display . end ( r ) ;
}
catch ( Error e ) {
print ( " failed to cast to wireless display: %s " , e . message ) ;
release ( ) ;
}
} ) ;
2017-03-25 09:47:51 +00:00
hold ( ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private unowned Device ? find_device_by_name ( string nic_name )
{
foreach ( var d in devices . get_values ( ) ) {
if ( nic_name = = d . interface ) {
return d ;
}
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
return null ;
}
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
private unowned Link ? find_link_by_name ( string nic_name )
{
foreach ( var l in links . get_values ( ) ) {
if ( nic_name = = l . interface_name ) {
return l ;
}
}
return null ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private unowned Sink ? find_sink_by_mac ( string m )
{
foreach ( var l in sinks . get_keys ( ) ) {
if ( l . has_prefix ( m ) ) {
return sinks . lookup ( l ) ;
}
}
return null ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private bool is_wnic ( string nic_name )
{
return find_link_by_name ( nic_name ) ! = null ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
private async void wait_prop_changed ( DBusProxy o ,
string name ,
uint timeout = 0 ) throws WfdCtlError
{
ulong prop_changed_id = o . g_properties_changed . connect ( ( props ) = > {
string k ;
Variant v ;
foreach ( var prop in props ) {
prop . get ( " {sv} " , out k , out v ) ;
if ( k = = name ) {
wait_prop_changed . callback ( ) ;
break ;
}
}
} ) ;
bool timed_out = false ;
uint timeout_id = 0 ;
if ( 0 < timeout ) {
timeout_id = Timeout . add_seconds ( timeout ,
( ) = > {
timed_out = true ;
wait_prop_changed . callback ( ) ;
return false ;
} ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
yield ;
if ( 0 < timeout ) {
Source . remove ( timeout_id ) ;
2017-03-22 03:12:43 +00:00
}
2017-03-22 14:43:35 +00:00
o . disconnect ( prop_changed_id ) ;
2017-03-22 03:12:43 +00:00
2017-03-22 14:43:35 +00:00
if ( timed_out ) {
throw new WfdCtlError . TIMEOUT ( " timeout to wait for property %s change " ,
name ) ;
}
}
2017-03-22 03:12:43 +00:00
}
int main ( string [ ] ? argv )
{
2017-03-22 14:43:35 +00:00
Gdk . init ( ref argv ) ;
2017-03-22 03:12:43 +00:00
Intl . setlocale ( ) ;
Environment . set_prgname ( Path . get_basename ( argv [ 0 ] ) ) ;
2017-03-25 09:47:51 +00:00
2017-03-22 14:43:35 +00:00
Application app = new WfdCtl ( ) ;
2017-03-22 03:12:43 +00:00
app . set_default ( ) ;
2017-03-25 09:47:51 +00:00
Sigint . add_watch ( ( app as WfdCtl ) . stop_wireless_display ) ;
2017-03-22 03:12:43 +00:00
try {
app . register ( ) ;
}
catch ( Error e ) {
print ( " failed to startup: %s " , e . message ) ;
return 1 ;
}
return app . run ( argv ) ;
}