GTK2-Perl程序示例:遠程桌面客戶端gtkremote

這個例子說明了如何將Glade界面直接放在程序中方便在郵件列表和論壇上直接發佈程序,以及如何用Gtk2::Helper調用網絡程序防止連接超時導致界面阻塞。程序中 用Expect實現了VNC密碼輸入。

 

  1. #! /usr/bin/perl -w 
  2.  
  3. #---------------------------------------------------------------------- 
  4. # gtkremote.pl  
  5. # A remote desktop frontend of Gtk2/GladeXML 
  6. # Copyright (C) 2008 Viperii ([email protected]
  7. #  This library is free software; you can redistribute it and/or 
  8. #  modify it under the terms of the GNU Lesser General Public 
  9. #  License as published by the Free Software Foundation; either 
  10. #  version 2 of the License, or (at your optionany later version. 
  11. #  
  12. #  This library is distributed in the hope that it will be useful, 
  13. #  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  15. #  Lesser General Public License for more details. 
  16. #   
  17. #  You should have received a copy of the GNU Lesser General Public 
  18. #  License along with this library; if not, write to the 
  19. #  Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
  20. #  Boston, MA 02111-1307, USA. 
  21. #---------------------------------------------------------------------- 
  22.  
  23. use strict; 
  24. use warnings; 
  25.  
  26. use Glib qw/TRUE FALSE/; 
  27. use Gtk2 '-init'
  28. use Gtk2::Helper; 
  29. use Gtk2::GladeXML; 
  30.  
  31. use FindBin qw($Bin); 
  32. use Expect; 
  33.  
  34. my $CMD; 
  35. my $PID; 
  36. my $TAG; 
  37. my $CONN = 0; 
  38. my $PREFIX = '@PREFIX@'
  39. my $BIN_DIR = (-d $PREFIX ? "$PREFIX/bin" : $Bin); 
  40. my $VNC_TMP = "/tmp/vncpasswd.tmp"
  41.  
  42. $| = 1; 
  43.  
  44. my $glade_data; {local $/ = undef; $glade_data = <DATA>;} 
  45. my $gladexml = Gtk2::GladeXML->new_from_buffer($glade_data); 
  46. #my $gladexml = Gtk2::GladeXML->new($BIN_DIR.'/gtkremote.glade'); 
  47. $gladexml->signal_autoconnect_from_package('main'); 
  48.  
  49. my $window = $gladexml->get_widget('main'); 
  50. my $host_entry = $gladexml->get_widget('entry1'); 
  51. my $port_entry = $gladexml->get_widget('entry2'); 
  52. my $user_entry = $gladexml->get_widget('entry3'); 
  53. my $pass_entry = $gladexml->get_widget('entry4'); 
  54. my $combobox = $gladexml->get_widget('combobox1'); 
  55. my $button = $gladexml->get_widget('button1'); 
  56. my $status_icon = $gladexml->get_widget('image2'); 
  57.  
  58. my @prot_list = ("VNC""RDP"); 
  59. $combobox->append_text($_) foreach (@prot_list); 
  60. $combobox->set_active(0); 
  61.  
  62. $window->show_all(); 
  63. Gtk2->main(); 
  64. $window->destroy; 
  65. exit 0; 
  66.  
  67. sub on_main_delete_event 
  68.     kill 15 => $PID if $PID; 
  69.     unlink $VNC_TMP if -f $VNC_TMP; 
  70.     Gtk2->main_quit; 
  71.     exit; 
  72.  
  73. sub on_combobox1_changed 
  74.     $combobox->get_active_text eq "VNC" ? $user_entry->set_sensitive(FALSE) : $user_entry->set_sensitive(TRUE); 
  75.  
  76. sub on_button1_clicked 
  77.     unless($CONN) 
  78.     { 
  79.     remote_connect(); 
  80.     } 
  81.     else 
  82.     { 
  83.     kill 15 => $PID if $PID; 
  84.     } 
  85.  
  86. sub status_connect 
  87.     $CONN = 1; 
  88.     $button->child->set_text("Disconnect"); 
  89.     $status_icon->set_from_stock('gtk-connect''large-toolbar'); 
  90.  
  91. sub status_disconnect 
  92.     $CONN = 0; 
  93.     $button->child->set_text("Connect"); 
  94.     $status_icon->set_from_stock('gtk-disconnect''large-toolbar'); 
  95.  
  96. sub message_dialog_show  
  97. #$icon can be: a) 'info' 
  98. #              b) 'warning' 
  99. #              c) 'error' 
  100. #              d) 'question' 
  101. #$button_type can be: a) 'none' 
  102. #                     b) 'ok' 
  103. #                     c) 'close' 
  104. #                     d) 'cancel' 
  105. #                     e) 'yes-no' 
  106. #                     f) 'ok-cancel' 
  107.  
  108.     my ($parent,$icon,$text,$button_type) = @_; 
  109.      
  110.     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent, 
  111.                                [qw/modal destroy-with-parent/], 
  112.                                $icon, 
  113.                                $button_type, 
  114.                                sprintf "$text"); 
  115.     my $retval = $dialog->run; 
  116.     $dialog->destroy; 
  117.     return $retval; 
  118.  
  119. sub remote_connect 
  120.     status_connect(); 
  121.  
  122.     my $host = $host_entry->get_text; 
  123.     my $port = $port_entry->get_text; 
  124.     my $user = $user_entry->get_text; 
  125.     my $pass = $pass_entry->get_text; 
  126.     my $prot = $combobox->get_active_text; 
  127.      
  128.     if($host) 
  129.     { 
  130.     if($prot eq "VNC"
  131.     { 
  132.         unlink $VNC_TMP if -f $VNC_TMP; 
  133.          
  134.         $CMD = "vncviewer $host"
  135.         $CMD .= "::$port" if $port =~ /^(\d+)$/; 
  136.         if(length($pass) >= 6) 
  137.         { 
  138.         my $sh = Expect->spawn('/bin/sh'or die "Cannot spawn shell: $!\n"
  139.         my $exp = new Expect; 
  140.         my $command = "vncpasswd $VNC_TMP"
  141.         $exp->spawn($command) or die "Cannot spawn $command: $!\n"
  142.         $exp->expect(10, 'Password:'); 
  143.         $exp->send("$pass\n"); 
  144.         $exp->expect(10, 'Verify:'); 
  145.         $exp->send("$pass\n");   
  146.         $exp->interact(); 
  147.         $exp->soft_close(); 
  148.         $sh->hard_close(); 
  149.  
  150.         $CMD .= " -passwd $VNC_TMP"
  151.         } 
  152.         else 
  153.         { 
  154.         message_dialog_show($window, 
  155.                     'error'
  156.                     'VNC password too short.'
  157.                     'ok' 
  158.             ); 
  159.         status_disconnect(); 
  160.         return
  161.         } 
  162.     } 
  163.     elsif($prot eq "RDP"
  164.     { 
  165.         $CMD = "rdesktop $host"
  166.         $CMD .= ":$port" if $port =~ /^(\d+)$/; 
  167.         $CMD .= " -u $user" if $user
  168.         $CMD .= " -p $pass" if $pass; 
  169.     } 
  170.     else 
  171.     { 
  172.         status_disconnect(); 
  173.         return
  174.     } 
  175.     } 
  176.     else 
  177.     { 
  178.     status_disconnect(); 
  179.     return
  180.     } 
  181.  
  182.     $PID = open my $pipe, '-|'"$CMD" or die "Failed open pipe: $CMD\n"
  183.      
  184.     $TAG = Gtk2::Helper->add_watch(fileno($pipe), in => sub  
  185.                    { 
  186.                        if(eof($pipe)) 
  187.                        { 
  188.                        Gtk2::Helper->remove_watch($TAG); 
  189.                        close($pipe); 
  190.                        unlink $VNC_TMP if -f $VNC_TMP; 
  191.                        status_disconnect(); 
  192.                        0; 
  193.                        } 
  194.                        else  
  195.                        { 
  196.                        #my $line = <$pipe>; # stdout string. 
  197.                        #print "OUTPUT: ".$line."\n" if $line; 
  198.                        } 
  199.                         
  200.                        1; 
  201.                    } ); 
  202.  
  203. __DATA__ 
  204. <?xml version="1.0" encoding="UTF-8" standalone="no"?> 
  205. <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"
  206. <!--Generated with glade3 3.4.0 on Wed Feb  6 18:08:05 2008 --> 
  207. <glade-interface> 
  208.   <widget class="GtkWindow" id="main"
  209.     <property name="visible">True</property> 
  210.     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  211.     <property name="window_position">GTK_WIN_POS_CENTER</property> 
  212.     <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> 
  213.     <signal name="delete_event" handler="on_main_delete_event"/> 
  214.     <child> 
  215.       <widget class="GtkHBox" id="hbox1"
  216.         <property name="visible">True</property> 
  217.         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  218.         <child> 
  219.           <widget class="GtkFixed" id="fixed5"
  220.             <property name="visible">True</property> 
  221.             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  222.             <child> 
  223.               <widget class="GtkImage" id="image1"
  224.                 <property name="width_request">71</property> 
  225.                 <property name="height_request">63</property> 
  226.                 <property name="visible">True</property> 
  227.                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  228.                 <property name="stock">gtk-network</property> 
  229.                 <property name="icon_size">6</property> 
  230.               </widget> 
  231.               <packing> 
  232.                 <property name="y">53</property> 
  233.               </packing> 
  234.             </child> 
  235.           </widget> 
  236.         </child> 
  237.         <child> 
  238.           <widget class="GtkVBox" id="vbox1"
  239.             <property name="visible">True</property> 
  240.             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  241.             <child> 
  242.               <widget class="GtkFixed" id="fixed2"
  243.                 <property name="visible">True</property> 
  244.                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  245.                 <child> 
  246.                   <widget class="GtkLabel" id="label1"
  247.                     <property name="width_request">39</property> 
  248.                     <property name="height_request">22</property> 
  249.                     <property name="visible">True</property> 
  250.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  251.                     <property name="label" translatable="yes">Host:</property> 
  252.                   </widget> 
  253.                   <packing> 
  254.                     <property name="x">1</property> 
  255.                     <property name="y">10</property> 
  256.                   </packing> 
  257.                 </child> 
  258.                 <child> 
  259.                   <widget class="GtkEntry" id="entry1"
  260.                     <property name="width_request">125</property> 
  261.                     <property name="height_request">25</property> 
  262.                     <property name="visible">True</property> 
  263.                     <property name="can_focus">True</property> 
  264.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  265.                   </widget> 
  266.                   <packing> 
  267.                     <property name="x">78</property> 
  268.                     <property name="y">10</property> 
  269.                   </packing> 
  270.                 </child> 
  271.                 <child> 
  272.                   <widget class="GtkLabel" id="label2"
  273.                     <property name="width_request">34</property> 
  274.                     <property name="height_request">23</property> 
  275.                     <property name="visible">True</property> 
  276.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  277.                     <property name="label" translatable="yes">Port:</property> 
  278.                   </widget> 
  279.                   <packing> 
  280.                     <property name="x">205</property> 
  281.                     <property name="y">10</property> 
  282.                   </packing> 
  283.                 </child> 
  284.                 <child> 
  285.                   <widget class="GtkEntry" id="entry2"
  286.                     <property name="width_request">50</property> 
  287.                     <property name="height_request">25</property> 
  288.                     <property name="visible">True</property> 
  289.                     <property name="can_focus">True</property> 
  290.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  291.                     <property name="max_length">5</property> 
  292.                   </widget> 
  293.                   <packing> 
  294.                     <property name="x">240</property> 
  295.                     <property name="y">10</property> 
  296.                   </packing> 
  297.                 </child> 
  298.               </widget> 
  299.             </child> 
  300.             <child> 
  301.               <widget class="GtkFixed" id="fixed4"
  302.                 <property name="visible">True</property> 
  303.                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  304.                 <child> 
  305.                   <widget class="GtkLabel" id="label3"
  306.                     <property name="width_request">61</property> 
  307.                     <property name="height_request">22</property> 
  308.                     <property name="visible">True</property> 
  309.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  310.                     <property name="label" translatable="yes">Protocol:</property> 
  311.                   </widget> 
  312.                   <packing> 
  313.                     <property name="y">7</property> 
  314.                   </packing> 
  315.                 </child> 
  316.                 <child> 
  317.                   <widget class="GtkComboBox" id="combobox1"
  318.                     <property name="width_request">86</property> 
  319.                     <property name="height_request">27</property> 
  320.                     <property name="visible">True</property> 
  321.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  322.                     <property name="items" translatable="yes"></property> 
  323.                     <signal name="changed" handler="on_combobox1_changed"/> 
  324.                   </widget> 
  325.                   <packing> 
  326.                     <property name="x">79</property> 
  327.                     <property name="y">6</property> 
  328.                   </packing> 
  329.                 </child> 
  330.               </widget> 
  331.               <packing> 
  332.                 <property name="position">1</property> 
  333.               </packing> 
  334.             </child> 
  335.             <child> 
  336.               <widget class="GtkFixed" id="fixed3"
  337.                 <property name="visible">True</property> 
  338.                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  339.                 <child> 
  340.                   <widget class="GtkLabel" id="label4"
  341.                     <property name="width_request">76</property> 
  342.                     <property name="height_request">22</property> 
  343.                     <property name="visible">True</property> 
  344.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  345.                     <property name="label" translatable="yes">Username:</property> 
  346.                   </widget> 
  347.                   <packing> 
  348.                     <property name="y">8</property> 
  349.                   </packing> 
  350.                 </child> 
  351.                 <child> 
  352.                   <widget class="GtkEntry" id="entry3"
  353.                     <property name="width_request">115</property> 
  354.                     <property name="height_request">25</property> 
  355.                     <property name="visible">True</property> 
  356.                     <property name="can_focus">True</property> 
  357.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  358.                     <property name="max_length">128</property> 
  359.                   </widget> 
  360.                   <packing> 
  361.                     <property name="x">79</property> 
  362.                     <property name="y">6</property> 
  363.                   </packing> 
  364.                 </child> 
  365.                 <child> 
  366.                   <widget class="GtkLabel" id="label5"
  367.                     <property name="width_request">71</property> 
  368.                     <property name="height_request">21</property> 
  369.                     <property name="visible">True</property> 
  370.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  371.                     <property name="label" translatable="yes">Password:</property> 
  372.                   </widget> 
  373.                   <packing> 
  374.                     <property name="y">36</property> 
  375.                   </packing> 
  376.                 </child> 
  377.                 <child> 
  378.                   <widget class="GtkEntry" id="entry4"
  379.                     <property name="width_request">115</property> 
  380.                     <property name="height_request">25</property> 
  381.                     <property name="visible">True</property> 
  382.                     <property name="can_focus">True</property> 
  383.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  384.                     <property name="max_length">128</property> 
  385.                     <property name="visibility">False</property> 
  386.                   </widget> 
  387.                   <packing> 
  388.                     <property name="x">79</property> 
  389.                     <property name="y">34</property> 
  390.                   </packing> 
  391.                 </child> 
  392.               </widget> 
  393.               <packing> 
  394.                 <property name="position">2</property> 
  395.               </packing> 
  396.             </child> 
  397.             <child> 
  398.               <widget class="GtkFixed" id="fixed1"
  399.                 <property name="visible">True</property> 
  400.                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  401.                 <child> 
  402.                   <widget class="GtkButton" id="button1"
  403.                     <property name="visible">True</property> 
  404.                     <property name="can_focus">True</property> 
  405.                     <property name="receives_default">True</property> 
  406.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  407.                     <property name="label" translatable="yes">Connect</property> 
  408.                     <property name="response_id">0</property> 
  409.                     <signal name="clicked" handler="on_button1_clicked"/> 
  410.                   </widget> 
  411.                   <packing> 
  412.                     <property name="x">77</property> 
  413.                     <property name="y">10</property> 
  414.                   </packing> 
  415.                 </child> 
  416.                 <child> 
  417.                   <widget class="GtkImage" id="image2"
  418.                     <property name="width_request">32</property> 
  419.                     <property name="height_request">32</property> 
  420.                     <property name="visible">True</property> 
  421.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  422.                     <property name="stock">gtk-disconnect</property> 
  423.                     <property name="icon_size">3</property> 
  424.                   </widget> 
  425.                   <packing> 
  426.                     <property name="x">3</property> 
  427.                     <property name="y">7</property> 
  428.                   </packing> 
  429.                 </child> 
  430.                 <child> 
  431.                   <widget class="GtkLayout" id="layout1"
  432.                     <property name="width_request">295</property> 
  433.                     <property name="height_request">10</property> 
  434.                     <property name="visible">True</property> 
  435.                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> 
  436.                   </widget> 
  437.                   <packing> 
  438.                     <property name="x">4</property> 
  439.                     <property name="y">43</property> 
  440.                   </packing> 
  441.                 </child> 
  442.               </widget> 
  443.               <packing> 
  444.                 <property name="position">3</property> 
  445.               </packing> 
  446.             </child> 
  447.           </widget> 
  448.           <packing> 
  449.             <property name="position">1</property> 
  450.           </packing> 
  451.         </child> 
  452.       </widget> 
  453.     </child> 
  454.   </widget> 
  455. </glade-interface> 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章