"Fossies" - the Fresh Open Source Software Archive

Member "gparted-1.3.1/src/Win_GParted.cc" (19 Jun 2021, 136873 Bytes) of package /linux/misc/gparted-1.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Win_GParted.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.3.0_vs_1.3.1.

    1 /* Copyright (C) 2004 Bart
    2  * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Curtis Gedak
    3  *
    4  *  This program is free software; you can redistribute it and/or modify
    5  *  it under the terms of the GNU General Public License as published by
    6  *  the Free Software Foundation; either version 2 of the License, or
    7  *  (at your option) any later version.
    8  *
    9  *  This program is distributed in the hope that it will be useful,
   10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  *  GNU General Public License for more details.
   13  *
   14  *  You should have received a copy of the GNU General Public License
   15  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
   16  */
   17 
   18 #include "Win_GParted.h"
   19 #include "Device.h"
   20 #include "Dialog_Progress.h"
   21 #include "DialogFeatures.h"
   22 #include "DialogPasswordEntry.h"
   23 #include "Dialog_Disklabel.h"
   24 #include "Dialog_Rescue_Data.h"
   25 #include "Dialog_Partition_Resize_Move.h"
   26 #include "Dialog_Partition_Copy.h"
   27 #include "Dialog_Partition_New.h"
   28 #include "Dialog_Partition_Info.h"
   29 #include "Dialog_FileSystem_Label.h"
   30 #include "Dialog_Partition_Name.h"
   31 #include "DialogManageFlags.h"
   32 #include "GParted_Core.h"
   33 #include "MenuHelpers.h"
   34 #include "Mount_Info.h"
   35 #include "OperationCopy.h"
   36 #include "OperationCheck.h"
   37 #include "OperationCreate.h"
   38 #include "OperationDelete.h"
   39 #include "OperationFormat.h"
   40 #include "OperationResizeMove.h"
   41 #include "OperationChangeUUID.h"
   42 #include "OperationLabelFileSystem.h"
   43 #include "OperationNamePartition.h"
   44 #include "Partition.h"
   45 #include "PartitionVector.h"
   46 #include "PasswordRAMStore.h"
   47 #include "LVM2_PV_Info.h"
   48 #include "LUKS_Info.h"
   49 #include "Utils.h"
   50 #include "../config.h"
   51 
   52 #include <string.h>
   53 #include <gtkmm/cssprovider.h>
   54 #include <gtkmm/aboutdialog.h>
   55 #include <gtkmm/messagedialog.h>
   56 #include <gtkmm/radiobuttongroup.h>
   57 #include <gtkmm/radiomenuitem.h>
   58 #include <gtkmm/main.h>
   59 #include <gtkmm/separator.h>
   60 #include <gtkmm/grid.h>
   61 #include <glibmm/ustring.h>
   62 #include <glibmm/miscutils.h>
   63 #include <glibmm/shell.h>
   64 #include <glibmm/main.h>
   65 
   66 
   67 namespace GParted
   68 {
   69     
   70 Win_GParted::Win_GParted( const std::vector<Glib::ustring> & user_devices )
   71 {
   72     copied_partition = NULL;
   73     selected_partition_ptr = NULL;
   74     new_count = 1;
   75     current_device = 0 ;
   76     OPERATIONSLIST_OPEN = true ;
   77     gparted_core .set_user_devices( user_devices ) ;
   78     
   79     TOOLBAR_NEW =
   80     TOOLBAR_DEL =
   81     TOOLBAR_RESIZE_MOVE =
   82     TOOLBAR_COPY =
   83     TOOLBAR_PASTE =
   84     TOOLBAR_UNDO =
   85     TOOLBAR_APPLY = -1;
   86 
   87     //==== GUI =========================
   88     this ->set_title( _("GParted") );
   89     this ->set_default_size( 775, 500 );
   90     
   91     try
   92     {
   93         this ->set_default_icon_name( "gparted" ) ;
   94     }
   95     catch ( Glib::Exception & e )
   96     {
   97         std::cout << e .what() << std::endl ;
   98     }
   99 
  100     // Pack the main box
  101     vbox_main.set_orientation(Gtk::ORIENTATION_VERTICAL);
  102     this ->add( vbox_main ); 
  103     
  104     //menubar....
  105     init_menubar() ;
  106     vbox_main .pack_start( menubar_main, Gtk::PACK_SHRINK );
  107     
  108     //toolbar....
  109     init_toolbar() ;
  110     vbox_main.pack_start( hbox_toolbar, Gtk::PACK_SHRINK );
  111     
  112     //drawingarea_visualdisk...  ( contains the visual representation of the disks )
  113     drawingarea_visualdisk .signal_partition_selected .connect( 
  114             sigc::mem_fun( this, &Win_GParted::on_partition_selected ) ) ;
  115     drawingarea_visualdisk .signal_partition_activated .connect( 
  116             sigc::mem_fun( this, &Win_GParted::on_partition_activated ) ) ;
  117     drawingarea_visualdisk .signal_popup_menu .connect( 
  118             sigc::mem_fun( this, &Win_GParted::on_partition_popup_menu ) );
  119     vbox_main .pack_start( drawingarea_visualdisk, Gtk::PACK_SHRINK ) ;
  120     
  121     //hpaned_main (NOTE: added to vpaned_main)
  122     init_hpaned_main() ;
  123     vpaned_main.set_orientation(Gtk::ORIENTATION_VERTICAL);
  124     vpaned_main .pack1( hpaned_main, true, true ) ;
  125     
  126     //vpaned_main....
  127     vbox_main .pack_start( vpaned_main );
  128     
  129     //device info...
  130     init_device_info() ;
  131     
  132     //operationslist...
  133     hbox_operations .signal_undo .connect( sigc::mem_fun( this, &Win_GParted::activate_undo ) ) ;
  134     hbox_operations .signal_clear .connect( sigc::mem_fun( this, &Win_GParted::clear_operationslist ) ) ;
  135     hbox_operations .signal_apply .connect( sigc::mem_fun( this, &Win_GParted::activate_apply ) ) ;
  136     hbox_operations .signal_close .connect( sigc::mem_fun( this, &Win_GParted::close_operationslist ) ) ;
  137     vpaned_main .pack2( hbox_operations, true, true ) ;
  138 
  139     //statusbar... 
  140     pulsebar .set_pulse_step( 0.01 );
  141     pulsebar.set_valign(Gtk::ALIGN_CENTER);
  142     statusbar.pack_end(pulsebar, true, true, 10);
  143     statusbar.set_homogeneous();
  144     vbox_main .pack_start( statusbar, Gtk::PACK_SHRINK );
  145     
  146     this ->show_all_children();
  147     
  148     //make sure harddisk information is closed..
  149     hpaned_main .get_child1() ->hide() ;
  150 
  151     add_custom_css();
  152 }
  153 
  154 Win_GParted::~Win_GParted()
  155 {
  156     delete copied_partition;
  157     copied_partition = NULL;
  158 }
  159 
  160 void Win_GParted::init_menubar() 
  161 {
  162     Gtk::MenuItem *item;
  163 
  164     //fill menubar_main and connect callbacks 
  165     //gparted
  166     menu = manage( new Gtk::Menu() ) ;
  167     image = Utils::mk_image(Gtk::Stock::REFRESH, Gtk::ICON_SIZE_MENU);
  168     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  169         _("_Refresh Devices"),
  170         Gtk::AccelKey("<control>r"),
  171         *image, 
  172         sigc::mem_fun(*this, &Win_GParted::menu_gparted_refresh_devices)));
  173     menu->append(*item);
  174     
  175     image = Utils::mk_image(Gtk::Stock::HARDDISK, Gtk::ICON_SIZE_MENU);
  176     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  177         _("_Devices"), *image));
  178     menu->append(*item);
  179     mainmenu_items[MENU_DEVICES] = item;
  180     
  181     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  182     menu->append(*item);
  183 
  184     item = manage(new GParted::Menu_Helpers::StockMenuElem(
  185         Gtk::Stock::QUIT, sigc::mem_fun(*this, &Win_GParted::menu_gparted_quit)));
  186     menu->append(*item);
  187 
  188     item = manage(new GParted::Menu_Helpers::MenuElem(
  189         _("_GParted"), *menu));
  190     menubar_main.append(*item);
  191     
  192     //edit
  193     menu = manage( new Gtk::Menu() ) ;
  194     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  195         _("_Undo Last Operation"), 
  196         Gtk::AccelKey("<control>z"),
  197         *Utils::mk_image(Gtk::Stock::UNDO, Gtk::ICON_SIZE_MENU),
  198         sigc::mem_fun(*this, &Win_GParted::activate_undo)));
  199     menu->append(*item);
  200     mainmenu_items[MENU_UNDO_OPERATION] = item;
  201 
  202     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  203         _("_Clear All Operations"), 
  204         *Utils::mk_image(Gtk::Stock::CLEAR, Gtk::ICON_SIZE_MENU),
  205         sigc::mem_fun(*this, &Win_GParted::clear_operationslist)));
  206     menu->append(*item);
  207     mainmenu_items[MENU_CLEAR_OPERATIONS] = item;
  208 
  209     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  210         _("_Apply All Operations"),
  211         Gtk::AccelKey(GDK_KEY_Return, Gdk::CONTROL_MASK),
  212         *Utils::mk_image(Gtk::Stock::APPLY, Gtk::ICON_SIZE_MENU),
  213         sigc::mem_fun(*this, &Win_GParted::activate_apply)));
  214     menu->append(*item);
  215     mainmenu_items[MENU_APPLY_OPERATIONS] = item;
  216 
  217     item = manage(new GParted::Menu_Helpers::MenuElem(
  218         _("_Edit"), *menu));
  219     menubar_main.append(*item);
  220     mainmenu_items[MENU_EDIT] = item;
  221 
  222     //view
  223     menu = manage( new Gtk::Menu() ) ;
  224 
  225     item = manage(new GParted::Menu_Helpers::CheckMenuElem(
  226         _("Device _Information"), sigc::mem_fun(*this, &Win_GParted::menu_view_harddisk_info)));
  227     menu->append(*item);
  228     mainmenu_items[MENU_DEVICE_INFORMATION] = item;
  229 
  230     item = manage(new GParted::Menu_Helpers::CheckMenuElem(
  231         _("Pending _Operations"), sigc::mem_fun(*this, &Win_GParted::menu_view_operations)));
  232     menu->append(*item);
  233     mainmenu_items[MENU_PENDING_OPERATIONS] = item;
  234 
  235     item = manage(new GParted::Menu_Helpers::MenuElem(
  236         _("_View"), *menu));
  237     menubar_main.append(*item);
  238 
  239     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  240     menu->append(*item);
  241 
  242     item = manage( new GParted::Menu_Helpers::MenuElem(
  243         _("_File System Support"), sigc::mem_fun(*this, &Win_GParted::menu_gparted_features)));
  244     menu->append(*item);
  245     mainmenu_items[MENU_VIEW] = item;
  246 
  247     //device
  248     menu = manage( new Gtk::Menu() ) ;
  249 
  250     item = manage(new GParted::Menu_Helpers::MenuElem(
  251         Glib::ustring(_("_Create Partition Table") ) + "...",
  252         sigc::mem_fun(*this, &Win_GParted::activate_disklabel)));
  253     menu->append(*item);
  254 
  255     item = manage(new GParted::Menu_Helpers::MenuElem(
  256         Glib::ustring(_("_Attempt Data Rescue") ) + "...",
  257         sigc::mem_fun(*this, &Win_GParted::activate_attempt_rescue_data)));
  258     menu->append(*item);
  259 
  260     item = manage(new GParted::Menu_Helpers::MenuElem(
  261         _("_Device"), *menu));
  262     menubar_main.append(*item);
  263     mainmenu_items[MENU_DEVICE] = item;
  264 
  265     //partition
  266     init_partition_menu() ;
  267 
  268     item = manage(new GParted::Menu_Helpers::MenuElem(
  269         _("_Partition"), menu_partition));
  270     menubar_main.append(*item);
  271     mainmenu_items[MENU_PARTITION] = item;
  272 
  273     //help
  274     menu = manage( new Gtk::Menu() ) ;
  275 
  276     item = manage(new GParted::Menu_Helpers::ImageMenuElem(
  277         _("_Contents"), 
  278         Gtk::AccelKey("F1"),
  279         *Utils::mk_image(Gtk::Stock::HELP, Gtk::ICON_SIZE_MENU),
  280         sigc::mem_fun(*this, &Win_GParted::menu_help_contents)));
  281     menu->append(*item);
  282 
  283     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  284     menu->append(*item);
  285 
  286     item = manage( new GParted::Menu_Helpers::StockMenuElem(
  287         Gtk::Stock::ABOUT, sigc::mem_fun(*this, &Win_GParted::menu_help_about)));
  288     menu->append(*item);
  289 
  290     item = manage(new GParted::Menu_Helpers::MenuElem(
  291         _("_Help"), *menu));
  292     menubar_main.append(*item);
  293 }
  294 
  295 void Win_GParted::init_toolbar() 
  296 {
  297     int index = 0 ;
  298     // Initialize and pack toolbar_main
  299     hbox_toolbar.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
  300     hbox_toolbar.pack_start( toolbar_main );
  301     
  302     //NEW and DELETE
  303     image = Utils::mk_image(Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON);
  304     /*TO TRANSLATORS: "New" is a tool bar item for partition actions. */
  305     Glib::ustring str_temp = _("New") ;
  306     toolbutton = Gtk::manage(new Gtk::ToolButton( *image, str_temp ));
  307     toolbutton ->signal_clicked() .connect( sigc::mem_fun( *this, &Win_GParted::activate_new ) );
  308     toolbar_main .append( *toolbutton );
  309     TOOLBAR_NEW = index++ ;
  310     toolbutton->set_tooltip_text(_("Create a new partition in the selected unallocated space"));
  311     image = Utils::mk_image(Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON);
  312     str_temp = Utils::get_stock_label(Gtk::Stock::DELETE);
  313     toolbutton = Gtk::manage(new Gtk::ToolButton(*image, str_temp));
  314     toolbutton->set_use_underline(true);
  315     toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_delete) );
  316     toolbar_main.append(*toolbutton);
  317     TOOLBAR_DEL = index++ ;
  318     toolbutton->set_tooltip_text(_("Delete the selected partition"));
  319     toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
  320     index++ ;
  321     
  322     //RESIZE/MOVE
  323     image = Utils::mk_image(Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_BUTTON);
  324     str_temp = _("Resize/Move") ;
  325     //Condition string split and Undo button.
  326     //  for longer translated string, split string in two and skip the Undo button to permit full toolbar to display
  327     //  FIXME:  Is there a better way to do this, perhaps without the conditional?  At the moment this seems to be the best compromise.
  328     bool display_undo = true ;
  329     if( str_temp .length() > 14 ) {
  330         size_t index = str_temp .find( "/" ) ;
  331         if ( index != Glib::ustring::npos ) {
  332             str_temp .replace( index, 1, "\n/" ) ;
  333             display_undo = false ;
  334         }
  335     }
  336     toolbutton = Gtk::manage(new Gtk::ToolButton( *image, str_temp ));
  337     toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_resize) );
  338     toolbar_main.append(*toolbutton);
  339     TOOLBAR_RESIZE_MOVE = index++ ;
  340     toolbutton->set_tooltip_text(_("Resize/Move the selected partition"));
  341     toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
  342     index++ ;
  343 
  344     //COPY and PASTE
  345     image = Utils::mk_image(Gtk::Stock::COPY, Gtk::ICON_SIZE_BUTTON);
  346     str_temp = Utils::get_stock_label(Gtk::Stock::COPY);
  347     toolbutton = Gtk::manage(new Gtk::ToolButton(*image, str_temp));
  348     toolbutton->set_use_underline(true);
  349     toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_copy) );
  350     toolbar_main.append(*toolbutton);
  351     TOOLBAR_COPY = index++ ;
  352     toolbutton->set_tooltip_text(_("Copy the selected partition to the clipboard"));
  353     image = Utils::mk_image(Gtk::Stock::PASTE, Gtk::ICON_SIZE_BUTTON);
  354     str_temp = Utils::get_stock_label(Gtk::Stock::PASTE);
  355     toolbutton = Gtk::manage(new Gtk::ToolButton(*image, str_temp));
  356     toolbutton->set_use_underline(true);
  357     toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_paste) );
  358     toolbar_main.append(*toolbutton);
  359     TOOLBAR_PASTE = index++ ;
  360     toolbutton->set_tooltip_text(_("Paste the partition from the clipboard"));
  361     toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
  362     index++ ;
  363     
  364     //UNDO and APPLY
  365     if ( display_undo ) {
  366         //Undo button is displayed only if translated language "Resize/Move" is not too long.  See above setting of this condition.
  367         image = Utils::mk_image(Gtk::Stock::UNDO, Gtk::ICON_SIZE_BUTTON);
  368         str_temp = Utils::get_stock_label(Gtk::Stock::UNDO);
  369         toolbutton = Gtk::manage(new Gtk::ToolButton(*image, str_temp));
  370         toolbutton->set_use_underline(true);
  371         toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_undo) );
  372         toolbar_main.append(*toolbutton);
  373         TOOLBAR_UNDO = index++ ;
  374         toolbutton ->set_sensitive( false );
  375         toolbutton->set_tooltip_text(_("Undo Last Operation"));
  376     }
  377 
  378     image = Utils::mk_image(Gtk::Stock::APPLY, Gtk::ICON_SIZE_BUTTON);
  379     str_temp = Utils::get_stock_label(Gtk::Stock::APPLY);
  380     toolbutton = Gtk::manage(new Gtk::ToolButton(*image, str_temp));
  381     toolbutton->set_use_underline(true);
  382     toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_apply) );
  383     toolbar_main.append(*toolbutton);
  384     TOOLBAR_APPLY = index++ ;
  385     toolbutton ->set_sensitive( false );
  386     toolbutton->set_tooltip_text(_("Apply All Operations"));
  387 
  388     //initialize and pack combo_devices
  389     liststore_devices = Gtk::ListStore::create( treeview_devices_columns ) ;
  390     combo_devices .set_model( liststore_devices ) ;
  391 
  392     combo_devices .pack_start( treeview_devices_columns .icon, false ) ;
  393     combo_devices .pack_start( treeview_devices_columns .device ) ;
  394     combo_devices .pack_start( treeview_devices_columns .size, false ) ;
  395     
  396     combo_devices_changed_connection =
  397         combo_devices .signal_changed() .connect( sigc::mem_fun(*this, &Win_GParted::combo_devices_changed) );
  398 
  399     hbox_toolbar .pack_start( combo_devices, Gtk::PACK_SHRINK ) ;
  400 }
  401 
  402 void Win_GParted::init_partition_menu() 
  403 {
  404     Gtk::MenuItem *item;
  405 
  406     //fill menu_partition
  407     image = Utils::mk_image(Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU);
  408     item = manage(new
  409             /*TO TRANSLATORS: "_New" is a sub menu item for the partition menu. */
  410             GParted::Menu_Helpers::ImageMenuElem(_("_New"),
  411                               Gtk::AccelKey(GDK_KEY_Insert, Gdk::BUTTON1_MASK),
  412                               *image,
  413                               sigc::mem_fun(*this, &Win_GParted::activate_new)));
  414     menu_partition.append(*item);
  415     partitionmenu_items[MENU_NEW] = item;
  416 
  417     item = manage(new
  418             GParted::Menu_Helpers::StockMenuElem(Gtk::Stock::DELETE,
  419                               Gtk::AccelKey(GDK_KEY_Delete, Gdk::BUTTON1_MASK),
  420                               sigc::mem_fun(*this, &Win_GParted::activate_delete)));
  421     menu_partition.append(*item);
  422     partitionmenu_items[MENU_DEL] = item;
  423 
  424     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  425     menu_partition.append(*item);
  426 
  427     image = Utils::mk_image(Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_MENU);
  428     item = manage(new
  429             GParted::Menu_Helpers::ImageMenuElem(_("_Resize/Move"),
  430                               *image, 
  431                               sigc::mem_fun(*this, &Win_GParted::activate_resize)));
  432     menu_partition.append(*item);
  433     partitionmenu_items[MENU_RESIZE_MOVE] = item;
  434     
  435     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  436     menu_partition.append(*item);
  437     
  438     item = manage(new
  439             GParted::Menu_Helpers::StockMenuElem(Gtk::Stock::COPY,
  440                               sigc::mem_fun(*this, &Win_GParted::activate_copy)));
  441     menu_partition.append(*item);
  442     partitionmenu_items[MENU_COPY] = item;
  443     
  444     item = manage(new
  445             GParted::Menu_Helpers::StockMenuElem(Gtk::Stock::PASTE,
  446                               sigc::mem_fun(*this, &Win_GParted::activate_paste)));
  447     menu_partition.append(*item);
  448     partitionmenu_items[MENU_PASTE] = item;
  449     
  450     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  451     menu_partition.append(*item);
  452 
  453     image = Utils::mk_image(Gtk::Stock::CONVERT, Gtk::ICON_SIZE_MENU);
  454     item = manage(new
  455             /*TO TRANSLATORS: menuitem which holds a submenu with file systems.. */
  456             GParted::Menu_Helpers::ImageMenuElem(_("_Format to"),
  457                               *image,
  458                               *create_format_menu()));
  459     menu_partition.append(*item);
  460     partitionmenu_items[MENU_FORMAT] = item;
  461     
  462     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  463     menu_partition.append(*item);
  464 
  465     item = manage(new
  466             // Placeholder text, replaced in set_valid_operations() before the menu is shown
  467             GParted::Menu_Helpers::MenuElem("--toggle crypt busy--",
  468                                          sigc::mem_fun(*this, &Win_GParted::toggle_crypt_busy_state)));
  469     menu_partition.append(*item);
  470     partitionmenu_items[MENU_TOGGLE_CRYPT_BUSY] = item;
  471 
  472     item = manage(new
  473             // Placeholder text, replaced in set_valid_operations() before the menu is shown
  474             GParted::Menu_Helpers::MenuElem("--toggle fs busy--",
  475                              sigc::mem_fun(*this, &Win_GParted::toggle_fs_busy_state)));
  476     menu_partition.append(*item);
  477     partitionmenu_items[MENU_TOGGLE_FS_BUSY] = item;
  478 
  479     item = manage(new
  480             /*TO TRANSLATORS: menuitem which holds a submenu with mount points.. */
  481             GParted::Menu_Helpers::MenuElem(_("_Mount on"), *manage(new Gtk::Menu())));
  482     menu_partition.append(*item);
  483     partitionmenu_items[MENU_MOUNT] = item;
  484 
  485     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  486     menu_partition.append(*item);
  487 
  488     item = manage(new
  489             GParted::Menu_Helpers::MenuElem(_("_Name Partition"),
  490                                          sigc::mem_fun(*this, &Win_GParted::activate_name_partition)));
  491     menu_partition.append(*item);
  492     partitionmenu_items[MENU_NAME_PARTITION] = item;
  493 
  494     item = manage(new
  495             GParted::Menu_Helpers::MenuElem(_("M_anage Flags"),
  496                              sigc::mem_fun(*this, &Win_GParted::activate_manage_flags)));
  497     menu_partition.append(*item);
  498     partitionmenu_items[MENU_FLAGS] = item;
  499 
  500     item = manage(new
  501             GParted::Menu_Helpers::MenuElem(_("C_heck"),
  502                              sigc::mem_fun(*this, &Win_GParted::activate_check)));
  503     menu_partition.append(*item);
  504     partitionmenu_items[MENU_CHECK] = item;
  505 
  506     item = manage(new
  507             GParted::Menu_Helpers::MenuElem(_("_Label File System"),
  508                                          sigc::mem_fun(*this, &Win_GParted::activate_label_filesystem)));
  509     menu_partition.append(*item);
  510     partitionmenu_items[MENU_LABEL_FILESYSTEM] = item;
  511 
  512     item = manage(new
  513             GParted::Menu_Helpers::MenuElem(_("New UU_ID"),
  514                              sigc::mem_fun(*this, &Win_GParted::activate_change_uuid)));
  515     menu_partition.append(*item);
  516     partitionmenu_items[MENU_CHANGE_UUID] = item;
  517 
  518     item = manage(new GParted::Menu_Helpers::SeparatorElem());
  519     menu_partition.append(*item);
  520 
  521     item = manage(new
  522             GParted::Menu_Helpers::StockMenuElem(Gtk::Stock::DIALOG_INFO,
  523                               sigc::mem_fun(*this, &Win_GParted::activate_info)));
  524     menu_partition.append(*item);
  525     partitionmenu_items[MENU_INFO] = item;
  526     
  527     menu_partition .accelerate( *this ) ;  
  528 }
  529 
  530 //Create the Partition --> Format to --> (file system list) menu
  531 Gtk::Menu * Win_GParted::create_format_menu()
  532 {
  533     const std::vector<FS> & fss = gparted_core .get_filesystems() ;
  534     menu = manage( new Gtk::Menu() ) ;
  535 
  536     for ( unsigned int t = 0 ; t < fss .size() ; t++ )
  537     {
  538         if (GParted_Core::supported_filesystem(fss[t].fstype) &&
  539             fss[t].fstype != FS_LUKS                            )
  540             create_format_menu_add_item(fss[t].fstype, fss[t].create);
  541     }
  542     //Add cleared at the end of the list
  543     create_format_menu_add_item( FS_CLEARED, true ) ;
  544 
  545     return menu ;
  546 }
  547 
  548 
  549 //Add one entry to the Partition --> Format to --> (file system list) menu
  550 void Win_GParted::create_format_menu_add_item(FSType fstype, bool activate)
  551 {
  552     Gtk::Box *hbox = manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
  553     //the colored square
  554     hbox->pack_start(*manage(new Gtk::Image(Utils::get_color_as_pixbuf(fstype, 16, 16))),
  555                      Gtk::PACK_SHRINK);
  556     //the label...
  557     hbox->pack_start(*Utils::mk_label(" " + Utils::get_filesystem_string(fstype)),
  558                      Gtk::PACK_SHRINK);
  559 
  560     Gtk::MenuItem *item = manage(new Gtk::MenuItem(*hbox));
  561     menu->append(*item);
  562     if ( activate )
  563         item->signal_activate().connect(
  564             sigc::bind<FSType>(sigc::mem_fun(*this, &Win_GParted::activate_format), fstype));
  565     else
  566         item->set_sensitive(false);
  567 }
  568 
  569 
  570 void Win_GParted::init_device_info()
  571 {
  572     vbox_info.set_orientation(Gtk::ORIENTATION_VERTICAL);
  573     vbox_info.set_spacing( 5 );
  574     int top = 0;
  575 
  576     //title
  577     vbox_info .pack_start( 
  578         * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Device Information") ) + "</b>" ),
  579         Gtk::PACK_SHRINK );
  580 
  581     //GENERAL DEVICE INFO
  582     Gtk::Grid *grid = manage(new Gtk::Grid());
  583     grid->set_column_spacing(10);
  584 
  585     // Model
  586     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Model:")) + "</b>"),
  587                  0, top, 1, 1);
  588     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  589     grid->attach(*device_info.back(), 1, top++, 1, 1);
  590 
  591     // Serial number
  592     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Serial:")) + "</b>"),
  593                  0, top, 1, 1);
  594     device_info.push_back( Utils::mk_label( "", true, false, true ) );
  595     grid->attach(*device_info.back(), 1, top++, 1, 1);
  596 
  597     // Size
  598     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Size:")) + "</b>"),
  599                  0, top, 1, 1);
  600     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  601     grid->attach(*device_info.back(), 1, top++, 1, 1);
  602 
  603     // Path
  604     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Path:")) + "</b>"),
  605                  0, top, 1, 1);
  606     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  607     grid->attach(*device_info.back(), 1, top++, 1, 1);
  608 
  609     vbox_info.pack_start(*grid, Gtk::PACK_SHRINK);
  610 
  611     //DETAILED DEVICE INFO
  612     top = 0;
  613     grid = manage(new Gtk::Grid());
  614     grid->set_column_spacing(10);
  615 
  616     // One blank line
  617     grid->attach(*Utils::mk_label(""), 1, top++, 1, 1);
  618 
  619     // Disktype
  620     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Partition table:")) + "</b>"),
  621                  0, top, 1, 1);
  622     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  623     grid->attach(*device_info.back(), 1, top++, 1, 1);
  624 
  625     // Heads
  626     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Heads:")) + "</b>"),
  627                  0, top, 1, 1);
  628     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  629     grid->attach(*device_info.back(), 1, top++, 1, 1);
  630 
  631     // Sectors / track
  632     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Sectors/track:")) + "</b>"),
  633                  0, top, 1, 1);
  634     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  635     grid->attach(*device_info.back(), 1, top++, 1, 1);
  636 
  637     // Cylinders
  638     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Cylinders:")) + "</b>"),
  639                  0, top, 1, 1);
  640     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  641     grid->attach(*device_info.back(), 1, top++, 1, 1);
  642 
  643     // Total sectors
  644     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Total sectors:")) + "</b>"),
  645                  0, top, 1, 1);
  646     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  647     grid->attach(*device_info.back(), 1, top++, 1, 1);
  648 
  649     // Sector size
  650     grid->attach(*Utils::mk_label(" <b>" + static_cast<Glib::ustring>(_("Sector size:")) + "</b>"),
  651                  0, top, 1, 1);
  652     device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
  653     grid->attach(*device_info.back(), 1, top++, 1, 1);
  654 
  655     vbox_info.pack_start(*grid, Gtk::PACK_SHRINK);
  656 }
  657 
  658 void Win_GParted::init_hpaned_main() 
  659 {
  660     hpaned_main.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
  661     //left scrollwindow (holds device info)
  662     scrollwindow = manage( new Gtk::ScrolledWindow() ) ;
  663     scrollwindow ->set_shadow_type( Gtk::SHADOW_ETCHED_IN );
  664     scrollwindow ->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
  665 #if HAVE_SET_PROPAGATE_NATURAL_WIDTH
  666     scrollwindow->set_propagate_natural_width(true);
  667 #endif
  668 
  669     hpaned_main .pack1( *scrollwindow, true, true );
  670     scrollwindow ->add( vbox_info );
  671 
  672     //right scrollwindow (holds treeview with partitions)
  673     scrollwindow = manage( new Gtk::ScrolledWindow() ) ;
  674     scrollwindow ->set_shadow_type( Gtk::SHADOW_ETCHED_IN );
  675     scrollwindow ->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
  676 #if HAVE_SET_PROPAGATE_NATURAL_WIDTH
  677     scrollwindow->set_propagate_natural_width(true);
  678 #endif
  679 
  680     //connect signals and add treeview_detail
  681     treeview_detail .signal_partition_selected .connect( sigc::mem_fun( this, &Win_GParted::on_partition_selected ) );
  682     treeview_detail .signal_partition_activated .connect( sigc::mem_fun( this, &Win_GParted::on_partition_activated ) );
  683     treeview_detail .signal_popup_menu .connect( sigc::mem_fun( this, &Win_GParted::on_partition_popup_menu ) );
  684     scrollwindow ->add( treeview_detail );
  685     hpaned_main .pack2( *scrollwindow, true, true );
  686 }
  687 
  688 void Win_GParted::add_custom_css()
  689 {
  690     Glib::RefPtr<Gdk::Screen> default_screen = Gdk::Screen::get_default();
  691     Glib::RefPtr<Gtk::CssProvider> provider = Gtk::CssProvider::create();
  692 
  693     Glib::ustring custom_css;
  694     if (gtk_get_minor_version() >= 20)
  695         custom_css = "progressbar progress, trough { min-height: 8px; }";
  696     else
  697         custom_css = "GtkProgressBar { -GtkProgressBar-min-horizontal-bar-height: 8px; }";
  698 
  699     try
  700     {
  701         provider->load_from_data(custom_css);
  702     }
  703     catch (Glib::Error& e)
  704     {
  705         std::cerr << e.what() << std::endl;
  706     }
  707 
  708     Gtk::StyleContext::add_provider_for_screen(default_screen,
  709                                                provider,
  710                                                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
  711 }
  712 
  713 void Win_GParted::refresh_combo_devices()
  714 {
  715     // Temporarily block the on change callback while re-creating the device list
  716     // behind the combobox to prevent flashing redraw by being redrawn with an empty
  717     // device list.
  718     combo_devices_changed_connection .block();
  719     liststore_devices ->clear() ;
  720     
  721     menu = manage( new Gtk::Menu() ) ;
  722     Gtk::RadioButtonGroup radio_group ;
  723     
  724     for ( unsigned int i = 0 ; i < devices .size( ) ; i++ )
  725     {
  726         //combo...
  727         treerow = *( liststore_devices ->append() ) ;
  728         treerow[ treeview_devices_columns .icon ] =
  729             Utils::mk_pixbuf(*this, Gtk::Stock::HARDDISK, Gtk::ICON_SIZE_LARGE_TOOLBAR);
  730         treerow[ treeview_devices_columns .device ] = devices[ i ] .get_path() ;
  731         treerow[ treeview_devices_columns .size ] = "(" + Utils::format_size( devices[ i ] .length, devices[ i ] .sector_size ) + ")" ; 
  732 
  733         // Devices submenu...
  734         Gtk::Box *hbox = manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
  735         hbox ->pack_start( * Utils::mk_label( devices[ i ] .get_path() ), Gtk::PACK_EXPAND_WIDGET ) ;
  736         hbox ->pack_start( * Utils::mk_label( "   (" + Utils::format_size( devices[ i ] .length, devices[ i ] .sector_size ) + ")" ),
  737                            Gtk::PACK_SHRINK ) ;
  738 
  739         Gtk::RadioMenuItem *item = manage(new Gtk::RadioMenuItem(radio_group));
  740         menu->append(*item);
  741         item->add(*hbox);
  742         item->signal_activate().connect(
  743             sigc::bind<unsigned int>( sigc::mem_fun(*this, &Win_GParted::radio_devices_changed), i ) ) ;
  744     }
  745 
  746     mainmenu_items[MENU_DEVICES]->unset_submenu();
  747 
  748     if (menu->get_children().size())
  749     {
  750         menu ->show_all() ;
  751         mainmenu_items[MENU_DEVICES]->set_submenu(*menu);
  752     }
  753 
  754     combo_devices_changed_connection .unblock();
  755     combo_devices .set_active( current_device ) ;
  756 }
  757 
  758 bool Win_GParted::pulsebar_pulse()
  759 {
  760     pulsebar.pulse();
  761     Glib::ustring tmp_msg = gparted_core .get_thread_status_message() ;
  762     if ( tmp_msg != "" ) {
  763         statusbar.pop();
  764         statusbar.push( tmp_msg );
  765     }
  766 
  767     return true;
  768 }
  769 
  770 void Win_GParted::show_pulsebar( const Glib::ustring & status_message ) 
  771 {
  772     pulsebar .show();
  773     statusbar .push( status_message) ;
  774     
  775     //disable all input stuff
  776     toolbar_main .set_sensitive( false ) ;
  777     menubar_main .set_sensitive( false ) ;
  778     combo_devices .set_sensitive( false ) ;
  779     menu_partition .set_sensitive( false ) ;
  780     treeview_detail .set_sensitive( false ) ;
  781     drawingarea_visualdisk .set_sensitive( false ) ;
  782         
  783     // connect pulse update timer
  784     pulsetimer = Glib::signal_timeout().connect( sigc::mem_fun(*this, &Win_GParted::pulsebar_pulse), 100 );
  785 }
  786 
  787 void Win_GParted::hide_pulsebar()
  788 {
  789     pulsetimer.disconnect();
  790     pulsebar .hide();
  791     statusbar .pop() ;
  792         
  793     //enable all disabled stuff
  794     toolbar_main .set_sensitive( true ) ;
  795     menubar_main .set_sensitive( true ) ;
  796     combo_devices .set_sensitive( true ) ;
  797     menu_partition .set_sensitive( true ) ;
  798     treeview_detail .set_sensitive( true ) ;
  799     drawingarea_visualdisk .set_sensitive( true ) ;
  800 }
  801 
  802 void Win_GParted::Fill_Label_Device_Info( bool clear ) 
  803 {
  804     if ( clear )
  805         for ( unsigned int t = 0 ; t < device_info .size( ) ; t++ )
  806             device_info[ t ] ->set_text( "" ) ;
  807         
  808     else
  809     {       
  810         short t = 0;
  811         
  812         //global info...
  813         device_info[ t++ ] ->set_text( devices[ current_device ] .model ) ;
  814         device_info[ t++ ] ->set_text( devices[current_device].serial_number );
  815         device_info[ t++ ] ->set_text( Utils::format_size( devices[ current_device ] .length, devices[ current_device ] .sector_size ) ) ;
  816         device_info[ t++ ] ->set_text( devices[current_device].get_path() );
  817 
  818         //detailed info
  819         device_info[ t++ ] ->set_text( devices[ current_device ] .disktype ) ;
  820         device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .heads ) );
  821         device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .sectors ) );
  822         device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .cylinders ) );
  823         device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .length ) );
  824         device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .sector_size ) );
  825     }
  826 }
  827 
  828 bool Win_GParted::on_delete_event( GdkEventAny *event )
  829 {
  830     return ! Quit_Check_Operations();
  831 }   
  832 
  833 void Win_GParted::Add_Operation( const Device & device, Operation * operation )
  834 {
  835     if ( operation )
  836     { 
  837         Glib::ustring error ;
  838         //Add any of the listed operations without further checking, but
  839         //  for the other operations (_CREATE, _RESIZE_MOVE and _COPY)
  840         //  ensure the partition is correctly aligned.
  841         //FIXME: this is becoming a mess.. maybe it's better to check if partition_new > 0
  842         if ( operation ->type == OPERATION_DELETE ||
  843              operation ->type == OPERATION_FORMAT ||
  844              operation ->type == OPERATION_CHECK ||
  845              operation ->type == OPERATION_CHANGE_UUID ||
  846              operation ->type == OPERATION_LABEL_FILESYSTEM ||
  847              operation ->type == OPERATION_NAME_PARTITION ||
  848              gparted_core.valid_partition(device, operation->get_partition_new(), error)
  849            )
  850         {
  851             operation ->create_description() ;
  852             operations.push_back( operation );
  853         }
  854         else
  855         {
  856             Gtk::MessageDialog dialog( *this,
  857                    _("Could not add this operation to the list"),
  858                    false,
  859                    Gtk::MESSAGE_ERROR,
  860                    Gtk::BUTTONS_OK,
  861                    true );
  862             dialog .set_secondary_text( error ) ;
  863 
  864             dialog .run() ;
  865         }
  866     }
  867 }
  868 
  869 // Try to merge the second operation into the first in the operations[] vector.
  870 bool Win_GParted::merge_two_operations( unsigned int first, unsigned int second )
  871 {
  872     unsigned int num_ops = operations.size();
  873     if ( first >= num_ops-1 )
  874         return false;
  875     if ( first >= second || second >= num_ops )
  876         return false;
  877 
  878     if ( operations[first]->merge_operations( *operations[second] ) )
  879     {
  880         remove_operation( second );
  881         return true;
  882     }
  883 
  884     return false;
  885 }
  886 
  887 // Try to merge pending operations in the operations[] vector using the specified merge
  888 // type.
  889 //
  890 // Summary of all the operation merging rules for each operation type coded into the
  891 // ::activate_*() methods:
  892 //
  893 // Operation type      Partition status    Merge type             Method
  894 // -----------------   ----------------    --------------------   -----------------
  895 // resize/move         Real                MERGE_LAST_WITH_PREV   activate_resize()
  896 // resize/move         New                 MERGE_LAST_WITH_ANY    activate_resize()
  897 // paste               *                   none                   activate_paste()
  898 // new                 *                   none                   activate_new()
  899 // delete              Real                none                   activate_delete()
  900 // delete              New                 MERGE_ALL_ADJACENT     activate_delete()
  901 // format              Real                MERGE_LAST_WITH_PREV   activate_format()
  902 // format              New                 MERGE_LAST_WITH_ANY    activate_format()
  903 // check               Real [1]            MERGE_LAST_WITH_ANY    activate_check()
  904 // label file system   Real [1]            MERGE_LAST_WITH_ANY    activate_label_filesystem()
  905 // name partition      Real [1]            MERGE_LAST_WITH_ANY    activate_name_partition()
  906 // new UUID            Real [1]            MERGE_LAST_WITH_ANY    activate_change_uuid()
  907 //
  908 // [1] The UI only allows these operations to be applied to real partitions; where as the
  909 //     other mergeable operations can be applied to both real partitions and new, pending
  910 //     create partitions.
  911 void Win_GParted::merge_operations( MergeType mergetype )
  912 {
  913     unsigned int num_ops = operations.size();
  914     if ( num_ops <= 1 )
  915         return;  // Nothing to merge.  One or fewer operations.
  916 
  917     switch ( mergetype )
  918     {
  919         case MERGE_LAST_WITH_PREV:
  920             merge_two_operations( num_ops-2, num_ops-1 );
  921             break;
  922 
  923         case MERGE_LAST_WITH_ANY:
  924             for ( unsigned int i = 0 ; i < num_ops-1 ; i ++ )
  925             {
  926                 if ( merge_two_operations( i, num_ops-1 ) )
  927                     break;
  928             }
  929             break;
  930 
  931         case MERGE_ALL_ADJACENT:
  932             // Must check against operations.size() as looping continues after
  933             // merging which might have reduced the number of items in the
  934             // vector.
  935             for ( unsigned int i = 0 ; i < operations.size()-1 ; i ++ )
  936             {
  937                 merge_two_operations( i, i+1 );
  938             }
  939             break;
  940     }
  941 }
  942 
  943 void Win_GParted::Refresh_Visual()
  944 {
  945     // How GParted displays partitions in the GUI and manages the lifetime and
  946     // ownership of that data:
  947     //
  948     // (1) Queries the devices and partitions on disk and refreshes the model.
  949     //
  950     //     Data owner: std::vector<Devices> Win_GParted::devices
  951     //     Lifetime:   Valid until the next call to Refresh_Visual()
  952     //     Call chain:
  953     //
  954     //         Win_GParted::menu_gparted_refresh_devices()
  955     //             gparted_core.set_devices( devices )
  956     //                 GParted_Core::set_devices_thread( devices )
  957     //                     devices.clear()
  958     //                     etc.
  959     //
  960     // (2) Takes a copy of the partitions for the device currently being shown in the
  961     //     GUI and visually applies pending operations.
  962     //
  963     //     Data owner: PartitionVector Win_GParted::display_partitions
  964     //     Lifetime:   Valid until the next call to Refresh_Visual().
  965     //     Function:   Refresh_Visual()
  966     //
  967     // (3) Loads the disk graphic and partition list with partitions to be shown in
  968     //     the GUI.  Both classes store pointers pointing back to each partition
  969     //     object in the vector of display partitions.
  970     //
  971     //     Aliases:   Win_GParted::display_partitions[]
  972     //     Call chain:
  973     //
  974     //         Win_GParted::Refresh_Visual()
  975     //             drawingarea_visualdisk.load_partitions( display_partitions, device_sectors )
  976     //                 DrawingAreaVisualDisk::set_static_data( ... )
  977     //             treeview_detail.load_partitions( display_partitions )
  978     //                 TreeView_Detail::create_row()
  979     //                 TreeView_Detail::load_partitions()
  980     //                     TreeView_Detail::create_row()
  981     //
  982     // (4) Selecting a partition in the disk graphic or in the partition list fires
  983     //     the callback which passes a pointer to the selected partition stored in
  984     //     step (3).  The callback saves the selected partition and calls the opposite
  985     //     class to update it's selection.
  986     //
  987     //     Data owner: const Partition * Win_GParted::selected_partition_ptr
  988     //     Aliases:    Win_GParted::display_partitions[]
  989     //     Lifetime:   Valid until the next call to Refresh_Visual().
  990     //     Call chain: (example clicking on a partition in the disk graphic)
  991     //
  992     //         DrawingAreaVisualDisk::on_button_press_event()
  993     //             DawingAreaVisualDisk::set_selected( visual_partitions, x, y )
  994     //                 signal_partition_selected.emit( ..., false )
  995     //                     Win_GParted::on_partition_selected( partition_ptr, src_is_treeview )
  996     //                         treeview_detail.set_selected( treestore_detail->children(), partition_ptr )
  997     //                             TreeView::set_selected( rows, partition_ptr, inside_extended )
  998     //                                 set_cursor()
  999     //                                 TreeView::set_selected( rows, partition_ptr, true )
 1000     //                                     set_cursor()
 1001     //
 1002     // (5) Each new operation is added to the vector of pending operations.
 1003     //     Eventually Refresh_Visual() is call to update the GUI.  This goes to step
 1004     //     (2) which visually reapplies all pending operations again, including the
 1005     //     newly added operation.
 1006     //
 1007     //     Data owner: std::vector<Operation *> Win_GParted::operations
 1008     //     Lifetime:   Valid until operations have been applied by
 1009     //                 GParted_Core::apply_operation_to_disk().  Specifically longer
 1010     //                 than the next call call to Refresh_Visual().
 1011     //     Call chain: (example setting a file system label)
 1012     //
 1013     //         Win_GParted::activate_label_filesystem()
 1014     //             Win_GParted::Add_Operation( operation )
 1015     //             Win_GParted::merge_operations( ... )
 1016     //             Win_GParted::show_operationslist()
 1017     //                 Win_GParted::Refresh_Visual()
 1018     //
 1019     // (6) Selecting a partition as a copy source makes a copy of that partition
 1020     //     object.
 1021     //
 1022     //     Data owner: Partition Win_GParted::copied_partition
 1023     //     Lifetime:   Valid until GParted closed or the device is removed.
 1024     //                 Specifically longer than the next call to Refresh_Visual().
 1025     //     Function:   Win_GParted::activate_copy()
 1026 
 1027     display_partitions = devices[current_device].partitions;
 1028 
 1029     //make all operations visible
 1030     for ( unsigned int t = 0 ; t < operations .size(); t++ )
 1031         if ( operations[ t ] ->device == devices[ current_device ] )
 1032             operations[t]->apply_to_visual( display_partitions );
 1033             
 1034     hbox_operations .load_operations( operations ) ;
 1035 
 1036     //set new statusbartext
 1037     statusbar .pop() ;
 1038     statusbar .push( Glib::ustring::compose( ngettext( "%1 operation pending"
 1039                                                , "%1 operations pending"
 1040                                                , operations .size()
 1041                                                )
 1042                                      , operations .size()
 1043                                      )
 1044                    );
 1045         
 1046     if ( ! operations .size() ) 
 1047         allow_undo_clear_apply( false ) ;
 1048 
 1049     // Refresh copy partition source as necessary and select the largest unallocated
 1050     // partition if there is one.
 1051     selected_partition_ptr = NULL;
 1052     Sector largest_unalloc_size = -1 ;
 1053     Sector current_size ;
 1054 
 1055     for ( unsigned int t = 0 ; t < display_partitions.size() ; t++ )
 1056     {
 1057         if ( copied_partition != NULL && display_partitions[t].get_path() == copied_partition->get_path() )
 1058         {
 1059             delete copied_partition;
 1060             copied_partition = display_partitions[t].clone();
 1061         }
 1062 
 1063         if (display_partitions[t].fstype == FS_UNALLOCATED)
 1064         {
 1065             current_size = display_partitions[t].get_sector_length();
 1066             if ( current_size > largest_unalloc_size )
 1067             {
 1068                 largest_unalloc_size = current_size;
 1069                 selected_partition_ptr = & display_partitions[t];
 1070             }
 1071         }
 1072 
 1073         if ( display_partitions[t].type == TYPE_EXTENDED )
 1074         {
 1075             for ( unsigned int u = 0 ; u < display_partitions[t].logicals.size() ; u ++ )
 1076             {
 1077                 if ( copied_partition != NULL &&
 1078                      display_partitions[t].logicals[u].get_path() == copied_partition->get_path() )
 1079                 {
 1080                     delete copied_partition;
 1081                     copied_partition = display_partitions[t].logicals[u].clone();
 1082                 }
 1083 
 1084                 if (display_partitions[t].logicals[u].fstype == FS_UNALLOCATED)
 1085                 {
 1086                     current_size = display_partitions[t].logicals[u].get_sector_length();
 1087                     if ( current_size > largest_unalloc_size )
 1088                     {
 1089                         largest_unalloc_size = current_size;
 1090                         selected_partition_ptr = & display_partitions[t].logicals[u];
 1091                     }
 1092                 }
 1093             }
 1094         }
 1095     }
 1096 
 1097     // frame visualdisk
 1098     drawingarea_visualdisk.load_partitions( display_partitions, devices[current_device].length );
 1099 
 1100     // treeview details
 1101     treeview_detail.load_partitions( display_partitions );
 1102 
 1103     set_valid_operations() ;
 1104 
 1105     // Process Gtk events to redraw visuals with reloaded partition details
 1106     while ( Gtk::Main::events_pending() )
 1107         Gtk::Main::iteration();
 1108 
 1109     if ( largest_unalloc_size >= 0 )
 1110     {
 1111         // Flashing redraw work around.  Inform visuals of selection of the
 1112         // largest unallocated partition after drawing those visuals above.
 1113         drawingarea_visualdisk.set_selected( selected_partition_ptr );
 1114         treeview_detail.set_selected( selected_partition_ptr );
 1115 
 1116         // Process Gtk events to draw selection
 1117         while ( Gtk::Main::events_pending() )
 1118             Gtk::Main::iteration();
 1119     }
 1120 }
 1121 
 1122 // Confirms that the pointer points to one of the partition objects in the vector of
 1123 // displayed partitions, Win_GParted::display_partitions[].
 1124 // Usage: g_assert( valid_display_partition_ptr( my_partition_ptr ) );
 1125 bool Win_GParted::valid_display_partition_ptr( const Partition * partition_ptr )
 1126 {
 1127     for ( unsigned int i = 0 ; i < display_partitions.size() ; i++ )
 1128     {
 1129         if ( & display_partitions[i] == partition_ptr )
 1130             return true;
 1131         else if ( display_partitions[i].type == TYPE_EXTENDED )
 1132         {
 1133             for ( unsigned int j = 0 ; j < display_partitions[i].logicals.size() ; j++ )
 1134             {
 1135                 if ( & display_partitions[i].logicals[j] == partition_ptr )
 1136                     return true;
 1137             }
 1138         }
 1139     }
 1140     return false;
 1141 }
 1142 
 1143 bool Win_GParted::Quit_Check_Operations()
 1144 {
 1145     if ( operations .size() )
 1146     {
 1147         Gtk::MessageDialog dialog( *this,
 1148                        _("Quit GParted?"),
 1149                        false,
 1150                        Gtk::MESSAGE_QUESTION,
 1151                        Gtk::BUTTONS_NONE,
 1152                        true );
 1153 
 1154         dialog .set_secondary_text( Glib::ustring::compose( ngettext( "%1 operation is currently pending."
 1155                                                               , "%1 operations are currently pending."
 1156                                                               , operations .size()
 1157                                                               )
 1158                                                     , operations .size()
 1159                                                     )
 1160                                   ) ;
 1161     
 1162         dialog .add_button( Gtk::Stock::QUIT, Gtk::RESPONSE_CLOSE );
 1163         dialog .add_button( Gtk::Stock::CANCEL,Gtk::RESPONSE_CANCEL );
 1164         
 1165         if ( dialog .run() == Gtk::RESPONSE_CANCEL )
 1166             return false;//don't close GParted
 1167     }
 1168 
 1169     return true; //close GParted
 1170 }
 1171 
 1172 void Win_GParted::set_valid_operations()
 1173 {
 1174     allow_new( false ); allow_delete( false ); allow_resize( false ); allow_copy( false );
 1175     allow_paste( false ); allow_format( false );
 1176     allow_toggle_crypt_busy_state( false ); allow_toggle_fs_busy_state( false );
 1177     allow_name_partition( false ); allow_manage_flags( false ); allow_check( false );
 1178     allow_label_filesystem( false ); allow_change_uuid( false ); allow_info( false );
 1179 
 1180     // Set default name for the open/close crypt menu item.
 1181     const FileSystem * luks_filesystem_object = gparted_core.get_filesystem_object( FS_LUKS );
 1182     g_assert( luks_filesystem_object != NULL );  // Bug: LUKS FileSystem object not found
 1183     dynamic_cast<Gtk::Label *>(partitionmenu_items[MENU_TOGGLE_CRYPT_BUSY]->get_child())
 1184         ->set_label( luks_filesystem_object->get_custom_text( CTEXT_ACTIVATE_FILESYSTEM ) );
 1185     // Set default name for the file system active/deactivate menu item.
 1186     dynamic_cast<Gtk::Label *>(partitionmenu_items[MENU_TOGGLE_FS_BUSY]->get_child())
 1187         ->set_label( FileSystem::get_generic_text( CTEXT_ACTIVATE_FILESYSTEM ) );
 1188 
 1189     partitionmenu_items[MENU_TOGGLE_FS_BUSY]->show();
 1190     partitionmenu_items[MENU_MOUNT]->hide();
 1191 
 1192     // No partition selected ...
 1193     if ( ! selected_partition_ptr )
 1194         return ;
 1195     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 1196 
 1197     // Reference to the Partition object directly containing the file system.
 1198     const Partition & selected_filesystem = selected_partition_ptr->get_filesystem_partition();
 1199 
 1200     // Get file system and LUKS encryption capabilities
 1201     const FS& fs_cap = gparted_core.get_fs(selected_filesystem.fstype);
 1202     const FS & enc_cap = gparted_core.get_fs( FS_LUKS );
 1203 
 1204     //if there's something, there's some info ;)
 1205     allow_info( true ) ;
 1206 
 1207     // Set appropriate name for the open/close crypt menu item.
 1208     if (selected_partition_ptr->fstype == FS_LUKS)
 1209     {
 1210         dynamic_cast<Gtk::Label *>(partitionmenu_items[MENU_TOGGLE_CRYPT_BUSY]->get_child())
 1211             ->set_label( luks_filesystem_object->get_custom_text(   selected_partition_ptr->busy
 1212                                                                   ? CTEXT_DEACTIVATE_FILESYSTEM
 1213                                                                   : CTEXT_ACTIVATE_FILESYSTEM ) );
 1214     }
 1215     // Set appropriate name for the file system active/deactivate menu item.
 1216     if (selected_partition_ptr->fstype != FS_LUKS || selected_partition_ptr->busy)
 1217     {
 1218         const FileSystem *filesystem_object = gparted_core.get_filesystem_object(selected_filesystem.fstype);
 1219         if ( filesystem_object )
 1220         {
 1221             dynamic_cast<Gtk::Label *>(partitionmenu_items[MENU_TOGGLE_FS_BUSY]->get_child())
 1222                 ->set_label( filesystem_object->get_custom_text(   selected_filesystem.busy
 1223                                                                  ? CTEXT_DEACTIVATE_FILESYSTEM
 1224                                                                  : CTEXT_ACTIVATE_FILESYSTEM ) );
 1225         }
 1226         else
 1227         {
 1228             dynamic_cast<Gtk::Label *>(partitionmenu_items[MENU_TOGGLE_FS_BUSY]->get_child())
 1229                 ->set_label( FileSystem::get_generic_text (  selected_filesystem.busy
 1230                                                            ? CTEXT_DEACTIVATE_FILESYSTEM
 1231                                                            : CTEXT_ACTIVATE_FILESYSTEM ) );
 1232         }
 1233     }
 1234 
 1235     // Only permit encryption open/close when available
 1236     if (selected_partition_ptr->status == STAT_REAL &&
 1237         selected_partition_ptr->fstype == FS_LUKS   &&
 1238         ! selected_filesystem.busy                    )
 1239         allow_toggle_crypt_busy_state( true );
 1240 
 1241     // Only permit file system mount/unmount and swapon/swapoff when available
 1242     if (    selected_partition_ptr->status == STAT_REAL
 1243          && selected_partition_ptr->type   != TYPE_EXTENDED
 1244          && selected_filesystem.fstype     != FS_LVM2_PV
 1245          && selected_filesystem.fstype     != FS_LINUX_SWRAID
 1246          && selected_filesystem.fstype     != FS_ATARAID
 1247          && selected_filesystem.fstype     != FS_LUKS
 1248          && (    selected_filesystem.busy
 1249               || selected_filesystem.get_mountpoints().size() /* Have mount point(s) */
 1250               || selected_filesystem.fstype == FS_LINUX_SWAP
 1251             )
 1252        )
 1253         allow_toggle_fs_busy_state( true );
 1254 
 1255     // Only permit LVM VG activate/deactivate if the PV is busy or a member of a VG.
 1256     // For now specifically allow activation of an exported VG, which LVM will fail
 1257     // with "Volume group "VGNAME" is exported", otherwise user won't know why the
 1258     // inactive PV can't be activated.
 1259     if (    selected_partition_ptr->status == STAT_REAL
 1260          && selected_filesystem.fstype     == FS_LVM2_PV      // Active VGNAME from mount point
 1261          && ( selected_filesystem.busy || selected_filesystem.get_mountpoints().size() > 0 )
 1262        )
 1263         allow_toggle_fs_busy_state( true );
 1264 
 1265     // Allow partition naming on devices that support it
 1266     if ( selected_partition_ptr->status == STAT_REAL          &&
 1267          devices[current_device].partition_naming_supported() &&
 1268          ( selected_partition_ptr->type == TYPE_PRIMARY  ||
 1269            selected_partition_ptr->type == TYPE_LOGICAL  ||
 1270            selected_partition_ptr->type == TYPE_EXTENDED    )    )
 1271         allow_name_partition( true );
 1272 
 1273     // Allow partition flag management
 1274     if ( selected_partition_ptr->status == STAT_REAL          &&
 1275          ( selected_partition_ptr->type == TYPE_PRIMARY  ||
 1276            selected_partition_ptr->type == TYPE_LOGICAL  ||
 1277            selected_partition_ptr->type == TYPE_EXTENDED    )    )
 1278         allow_manage_flags( true );
 1279 
 1280 #ifdef ENABLE_ONLINE_RESIZE
 1281     // Online resizing always required the ability to update the partition table ...
 1282     if ( ! devices[current_device].readonly &&
 1283          selected_filesystem.busy              )
 1284     {
 1285         // Can the plain file system be online resized?
 1286         if (selected_partition_ptr->fstype != FS_LUKS    &&
 1287             (fs_cap.online_grow || fs_cap.online_shrink)   )
 1288             allow_resize( true );
 1289         // Is resizing an open LUKS mapping and the online file system within
 1290         // supported?
 1291         if ( selected_partition_ptr->fstype == FS_LUKS                &&
 1292              selected_partition_ptr->busy                             &&
 1293              ( ( enc_cap.online_grow && fs_cap.online_grow )     ||
 1294                ( enc_cap.online_shrink && fs_cap.online_shrink )    )    )
 1295             allow_resize( true );
 1296         // Always allow an extended partition to be resized online.
 1297         if (selected_partition_ptr->type == TYPE_EXTENDED)
 1298             allow_resize(true);
 1299     }
 1300 #endif
 1301 
 1302     // Only unmount/swapoff/VG deactivate or online actions allowed if busy
 1303     if ( selected_filesystem.busy )
 1304         return ;
 1305 
 1306     // UNALLOCATED space within a partition table or UNALLOCATED whole disk device
 1307     if (selected_partition_ptr->fstype == FS_UNALLOCATED)
 1308         allow_new( true );
 1309 
 1310     // UNALLOCATED space within a partition table
 1311     if ( selected_partition_ptr->type == TYPE_UNALLOCATED )
 1312     {
 1313         // Find out if there is a partition to be copied and if it fits inside this unallocated space
 1314         // FIXME:
 1315         // Temporarily disable copying of encrypted content into new partitions
 1316         // which can't yet be encrypted, until full LUKS read-write support is
 1317         // implemented.
 1318         if ( copied_partition             != NULL    &&
 1319              ! devices[current_device].readonly      &&
 1320              copied_partition->fstype     != FS_LUKS    )
 1321         {
 1322             const Partition & copied_filesystem_ptn = copied_partition->get_filesystem_partition();
 1323             Byte_Value required_size ;
 1324             if (copied_filesystem_ptn.fstype == FS_XFS)
 1325                 required_size = copied_filesystem_ptn.estimated_min_size() *
 1326                                 copied_filesystem_ptn.sector_size;
 1327             else
 1328                 required_size = copied_filesystem_ptn.get_byte_length();
 1329 
 1330             //Determine if space is needed for the Master Boot Record or
 1331             //  the Extended Boot Record.  Generally an an additional track or MEBIBYTE
 1332             //  is required so for our purposes reserve a MEBIBYTE in front of the partition.
 1333             //  NOTE:  This logic also contained in Dialog_Base_Partition::MB_Needed_for_Boot_Record
 1334             if (   (   selected_partition_ptr->inside_extended
 1335                     && selected_partition_ptr->type == TYPE_UNALLOCATED
 1336                    )
 1337                 || ( selected_partition_ptr->type == TYPE_LOGICAL )
 1338                                                  /* Beginning of disk device */
 1339                 || ( selected_partition_ptr->sector_start <= (MEBIBYTE / selected_partition_ptr->sector_size) )
 1340                )
 1341                 required_size += MEBIBYTE;
 1342 
 1343             //Determine if space is needed for the Extended Boot Record for a logical partition
 1344             //  after this partition.  Generally an an additional track or MEBIBYTE
 1345             //  is required so for our purposes reserve a MEBIBYTE in front of the partition.
 1346             if (   (   (   selected_partition_ptr->inside_extended
 1347                         && selected_partition_ptr->type == TYPE_UNALLOCATED
 1348                        )
 1349                     || ( selected_partition_ptr->type == TYPE_LOGICAL )
 1350                    )
 1351                 && ( selected_partition_ptr->sector_end
 1352                      < ( devices[ current_device ] .length
 1353                          - ( 2 * MEBIBYTE / devices[ current_device ] .sector_size )
 1354                        )
 1355                    )
 1356                )
 1357                 required_size += MEBIBYTE;
 1358 
 1359             //Determine if space is needed for the backup partition on a GPT partition table
 1360             if (   ( devices[ current_device ] .disktype == "gpt" )
 1361                 && ( ( devices[current_device].length - selected_partition_ptr->sector_end )
 1362                      < ( MEBIBYTE / devices[ current_device ] .sector_size )
 1363                    )
 1364                )
 1365                 required_size += MEBIBYTE ;
 1366 
 1367             if ( required_size <= selected_partition_ptr->get_byte_length() )
 1368                 allow_paste( true ) ;
 1369         }
 1370         
 1371         return ;
 1372     }
 1373     
 1374     // EXTENDED
 1375     if ( selected_partition_ptr->type == TYPE_EXTENDED )
 1376     {
 1377         // Deletion is only allowed when there are no logical partitions inside.
 1378         if ( selected_partition_ptr->logicals.size()      == 1                &&
 1379              selected_partition_ptr->logicals.back().type == TYPE_UNALLOCATED    )
 1380             allow_delete( true ) ;
 1381         
 1382         if ( ! devices[ current_device ] .readonly )
 1383             allow_resize( true ) ; 
 1384 
 1385         return ;
 1386     }   
 1387     
 1388     // PRIMARY, LOGICAL and UNPARTITIONED; partitions with supported file system.
 1389     if ( ( selected_partition_ptr->type == TYPE_PRIMARY       ||
 1390            selected_partition_ptr->type == TYPE_LOGICAL       ||
 1391            selected_partition_ptr->type == TYPE_UNPARTITIONED    ) &&
 1392          selected_partition_ptr->fstype != FS_UNALLOCATED             )
 1393     {
 1394         allow_format( true ) ;
 1395 
 1396         // Only allow deletion of inactive partitions within a partition table.
 1397         if ( ( selected_partition_ptr->type == TYPE_PRIMARY ||
 1398                selected_partition_ptr->type == TYPE_LOGICAL    ) &&
 1399              ! selected_partition_ptr->busy                         )
 1400             allow_delete( true );
 1401 
 1402         // Resizing/moving always requires the ability to update the partition
 1403         // table ...
 1404         if ( ! devices[current_device].readonly )
 1405         {
 1406             // Can the plain file system be resized or moved?
 1407             if (selected_partition_ptr->fstype != FS_LUKS     &&
 1408                 (fs_cap.grow || fs_cap.shrink || fs_cap.move)   )
 1409                 allow_resize( true );
 1410             // Is growing or moving this closed LUKS mapping permitted?
 1411             if (selected_partition_ptr->fstype == FS_LUKS &&
 1412                 ! selected_partition_ptr->busy            &&
 1413                 (enc_cap.grow || enc_cap.move)              )
 1414                 allow_resize( true );
 1415             // Is resizing an open LUKS mapping and the file system within
 1416             // supported?
 1417             if ( selected_partition_ptr->fstype == FS_LUKS         &&
 1418                  selected_partition_ptr->busy                      &&
 1419                          ( ( enc_cap.online_grow && fs_cap.grow )     ||
 1420                    ( enc_cap.online_shrink && fs_cap.shrink )    )    )
 1421                 allow_resize( true );
 1422         }
 1423 
 1424         // Only allow copying of real partitions, excluding closed encryption
 1425         // (which are only copied while open).
 1426         if (selected_partition_ptr->status == STAT_REAL &&
 1427             selected_filesystem.fstype     != FS_LUKS   &&
 1428             fs_cap.copy                                   )
 1429             allow_copy( true ) ;
 1430         
 1431         //only allow labelling of real partitions that support labelling
 1432         if ( selected_partition_ptr->status == STAT_REAL && fs_cap.write_label )
 1433             allow_label_filesystem( true );
 1434 
 1435         //only allow changing UUID of real partitions that support it
 1436         if ( selected_partition_ptr->status == STAT_REAL && fs_cap.write_uuid )
 1437             allow_change_uuid( true ) ;
 1438 
 1439         // Generate Mount on submenu, except for LVM2 PVs borrowing mount point to
 1440         // display the VGNAME and read-only supported LUKS.
 1441         if (selected_filesystem.fstype != FS_LVM2_PV     &&
 1442             selected_filesystem.fstype != FS_LUKS        &&
 1443             selected_filesystem.get_mountpoints().size()   )
 1444         {
 1445             partitionmenu_items[MENU_MOUNT]->unset_submenu();
 1446 
 1447             Gtk::Menu *menu = manage(new Gtk::Menu());
 1448             std::vector<Glib::ustring> temp_mountpoints = selected_filesystem.get_mountpoints();
 1449             for ( unsigned int t = 0 ; t < temp_mountpoints.size() ; t++ )
 1450             {
 1451                 Gtk::MenuItem *item;
 1452 
 1453                 item = manage(new
 1454                     GParted::Menu_Helpers::MenuElem(
 1455                         temp_mountpoints[t],
 1456                         sigc::bind<unsigned int>(sigc::mem_fun(*this, &Win_GParted::activate_mount_partition), t)));
 1457                 menu->append(*item);
 1458 
 1459                 dynamic_cast<Gtk::Label *>(item->get_child())->set_use_underline(false);
 1460             }
 1461             partitionmenu_items[MENU_MOUNT]->set_submenu(*menu);
 1462 
 1463             partitionmenu_items[MENU_TOGGLE_FS_BUSY]->hide();
 1464             partitionmenu_items[MENU_MOUNT]->show();
 1465         }
 1466 
 1467         // See if there is a partition to be copied and it fits inside this selected partition
 1468         if ( copied_partition != NULL                                              &&
 1469              ( copied_partition->get_filesystem_partition().get_byte_length() <=
 1470                selected_filesystem.get_byte_length()                             ) &&
 1471              selected_partition_ptr->status == STAT_REAL                           &&
 1472              *copied_partition != *selected_partition_ptr                             )
 1473             allow_paste( true );
 1474 
 1475         //see if we can somehow check/repair this file system....
 1476         if ( selected_partition_ptr->status == STAT_REAL && fs_cap.check )
 1477             allow_check( true ) ;
 1478     }
 1479 }
 1480 
 1481 void Win_GParted::show_operationslist()
 1482 {
 1483     //Enable (or disable) Undo and Apply buttons
 1484     allow_undo_clear_apply( operations .size() ) ;
 1485 
 1486     //Updates view of operations list and sensitivity of Undo and Apply buttons
 1487     Refresh_Visual();
 1488 
 1489     if ( operations .size() == 1 ) //first operation, open operationslist
 1490         open_operationslist() ;
 1491 
 1492     //FIXME:  A slight flicker may be introduced by this extra display refresh.
 1493     //An extra display refresh seems to prevent the disk area visual disk from
 1494     //  disappearing when enough operations are added to require a scrollbar
 1495     //  (about 4 operations with default window size).
 1496     //  Note that commenting out the code to
 1497     //  "//make scrollwindow focus on the last operation in the list"
 1498     //  in HBoxOperations::load_operations() prevents this problem from occurring as well.
 1499     //  See also Win_GParted::activate_undo().
 1500     drawingarea_visualdisk .queue_draw() ;
 1501 }
 1502 
 1503 void Win_GParted::open_operationslist() 
 1504 {
 1505     if ( ! OPERATIONSLIST_OPEN )
 1506     {
 1507         OPERATIONSLIST_OPEN = true ;
 1508         hbox_operations .show() ;
 1509     
 1510         for ( int t = vpaned_main .get_height() ; t > ( vpaned_main .get_height() - 100 ) ; t -= 5 )
 1511         {
 1512             vpaned_main .set_position( t );
 1513             while ( Gtk::Main::events_pending() ) 
 1514                 Gtk::Main::iteration() ;
 1515         }
 1516 
 1517         static_cast<Gtk::CheckMenuItem *>(mainmenu_items[MENU_PENDING_OPERATIONS])
 1518             ->set_active( true ) ;
 1519     }
 1520 }
 1521 
 1522 void Win_GParted::close_operationslist() 
 1523 {
 1524     if ( OPERATIONSLIST_OPEN )
 1525     {
 1526         OPERATIONSLIST_OPEN = false ;
 1527         
 1528         for ( int t = vpaned_main .get_position() ; t < vpaned_main .get_height() ; t += 5 )
 1529         {
 1530             vpaned_main .set_position( t ) ;
 1531         
 1532             while ( Gtk::Main::events_pending() )
 1533                 Gtk::Main::iteration();
 1534         }
 1535         
 1536         hbox_operations .hide() ;
 1537 
 1538         static_cast<Gtk::CheckMenuItem *>(mainmenu_items[MENU_PENDING_OPERATIONS])
 1539             ->set_active( false ) ;
 1540     }
 1541 }
 1542 
 1543 void Win_GParted::clear_operationslist() 
 1544 {
 1545     remove_operation( -1, true ) ;
 1546     close_operationslist() ;
 1547 
 1548     Refresh_Visual() ;
 1549 }
 1550 
 1551 void Win_GParted::combo_devices_changed()
 1552 {
 1553     unsigned int old_current_device = current_device;
 1554     //set new current device
 1555     current_device = combo_devices .get_active_row_number() ;
 1556     if ( current_device == (unsigned int) -1 )
 1557         current_device = old_current_device;
 1558     if ( current_device >= devices .size() )
 1559         current_device = 0 ;
 1560     set_title( Glib::ustring::compose( _("%1 - GParted"), devices[ current_device ] .get_path() ) );
 1561     
 1562     //refresh label_device_info
 1563     Fill_Label_Device_Info();
 1564     
 1565     //rebuild visualdisk and treeview
 1566     Refresh_Visual();
 1567     
 1568     // Update radio buttons..
 1569     if (mainmenu_items[MENU_DEVICES]->has_submenu())
 1570     {
 1571         static_cast<Gtk::RadioMenuItem *>
 1572         (mainmenu_items[MENU_DEVICES]->get_submenu()->get_children()[current_device])
 1573             ->set_active(true);
 1574     }
 1575 }
 1576 
 1577 void Win_GParted::radio_devices_changed( unsigned int item ) 
 1578 {
 1579     if (static_cast<Gtk::RadioMenuItem *>
 1580         (mainmenu_items[MENU_DEVICES]->get_submenu()->get_children()[item])->get_active())
 1581     {
 1582         combo_devices .set_active( item ) ;
 1583     }
 1584 }
 1585 
 1586 void Win_GParted::on_show()
 1587 {
 1588     Gtk::Window::on_show() ;
 1589     
 1590     vpaned_main .set_position( vpaned_main .get_height() ) ;
 1591     close_operationslist() ;
 1592 
 1593     // Register callback for as soon as the main window has been shown to perform the
 1594     // first load of the disk device details.  Do it this way because the Gtk  main
 1595     // loop doesn't seem to enable quit handling until on_show(), this function, has
 1596     // drawn the main window for the first time and returned, and we want Close Window
 1597     // [Alt-F4] to work during the initial load of the disk device details.
 1598     g_idle_add( initial_device_refresh, this );
 1599 }
 1600 
 1601 // Callback used to load the disk device details for the first time
 1602 gboolean Win_GParted::initial_device_refresh( gpointer data )
 1603 {
 1604     Win_GParted *win_gparted = static_cast<Win_GParted *>( data );
 1605     win_gparted->menu_gparted_refresh_devices();
 1606     return false;  // one shot g_idle_add() callback
 1607 }
 1608 
 1609 void Win_GParted::menu_gparted_refresh_devices()
 1610 {
 1611     show_pulsebar( _("Scanning all devices...") ) ;
 1612     gparted_core.set_devices( devices );
 1613     hide_pulsebar();
 1614     
 1615     //check if current_device is still available (think about hotpluggable stuff like usbdevices)
 1616     if ( current_device >= devices .size() )
 1617         current_device = 0 ;
 1618 
 1619     //see if there are any pending operations on non-existent devices
 1620     //NOTE that this isn't 100% foolproof since some stuff (e.g. sourcedevice of copy) may slip through.
 1621     //but anyone who removes the sourcedevice before applying the operations gets what he/she deserves :-)
 1622     //FIXME: this actually sucks ;) see if we can use STL predicates here..
 1623     unsigned int i ;
 1624     for ( unsigned int t = 0 ; t < operations .size() ; t++ )
 1625     {
 1626         for ( i = 0 ; i < devices .size() && devices[ i ] != operations[ t ] ->device ; i++ ) {}
 1627         
 1628         if ( i >= devices .size() )
 1629             remove_operation( t-- ) ;
 1630     }
 1631         
 1632     //if no devices were detected we disable some stuff and show a message in the statusbar
 1633     if ( devices .empty() )
 1634     {
 1635         this ->set_title( _("GParted") );
 1636         combo_devices .hide() ;
 1637         
 1638         mainmenu_items[MENU_DEVICES]->set_sensitive(false);
 1639         mainmenu_items[MENU_EDIT]->set_sensitive(false);
 1640         mainmenu_items[MENU_VIEW]->set_sensitive(false);
 1641         mainmenu_items[MENU_DEVICE]->set_sensitive(false);
 1642         mainmenu_items[MENU_PARTITION]->set_sensitive(false);
 1643         toolbar_main .set_sensitive( false ) ;
 1644         drawingarea_visualdisk .set_sensitive( false ) ;
 1645         treeview_detail .set_sensitive( false ) ;
 1646 
 1647         Fill_Label_Device_Info( true ) ;
 1648         
 1649         drawingarea_visualdisk .clear() ;
 1650         treeview_detail .clear() ;
 1651         
 1652         //hmzz, this is really paranoid, but i think it's the right thing to do ;)
 1653         hbox_operations .clear() ;
 1654         close_operationslist() ;
 1655         remove_operation( -1, true ) ;
 1656         
 1657         statusbar .pop() ;
 1658         statusbar .push( _( "No devices detected" ) );
 1659     }
 1660     else //at least one device detected
 1661     {
 1662         combo_devices .show() ;
 1663         
 1664         mainmenu_items[MENU_DEVICES]->set_sensitive(true);
 1665         mainmenu_items[MENU_EDIT]->set_sensitive(true);
 1666         mainmenu_items[MENU_VIEW]->set_sensitive(true);
 1667         mainmenu_items[MENU_DEVICE]->set_sensitive(true);
 1668         mainmenu_items[MENU_PARTITION]->set_sensitive(true);
 1669 
 1670         toolbar_main .set_sensitive( true ) ;
 1671         drawingarea_visualdisk .set_sensitive( true ) ;
 1672         treeview_detail .set_sensitive( true ) ;
 1673         
 1674         refresh_combo_devices() ;   
 1675     }
 1676 }
 1677 
 1678 void Win_GParted::menu_gparted_features()
 1679 {
 1680     DialogFeatures dialog ;
 1681     dialog .set_transient_for( *this ) ;
 1682 
 1683     dialog.load_filesystems(gparted_core.get_filesystems());
 1684     while ( dialog .run() == Gtk::RESPONSE_OK )
 1685     {
 1686         // Button [Rescan For Supported Actions] pressed in the dialog.  Rescan
 1687         // for available core and file system specific commands and update the
 1688         // view accordingly in the dialog.
 1689         GParted_Core::find_supported_core();
 1690         gparted_core .find_supported_filesystems() ;
 1691         dialog.load_filesystems(gparted_core.get_filesystems());
 1692 
 1693         //recreate format menu...
 1694         partitionmenu_items[MENU_FORMAT]->unset_submenu();
 1695         partitionmenu_items[MENU_FORMAT]->set_submenu(*create_format_menu());
 1696         partitionmenu_items[MENU_FORMAT]->get_submenu()->show_all_children();
 1697 
 1698         // Update valid operations for the currently selected partition.
 1699         set_valid_operations();
 1700     }
 1701 }
 1702 
 1703 void Win_GParted::menu_gparted_quit()
 1704 {
 1705     if ( Quit_Check_Operations() )
 1706         this ->hide();
 1707 }
 1708 
 1709 void Win_GParted::menu_view_harddisk_info()
 1710 { 
 1711     if (static_cast<Gtk::CheckMenuItem *>(mainmenu_items[MENU_DEVICE_INFORMATION])->get_active())
 1712     {   //open harddisk information
 1713         hpaned_main .get_child1() ->show() ;        
 1714         for ( int t = hpaned_main .get_position() ; t < 250 ; t += 15 )
 1715         {
 1716             hpaned_main .set_position( t );
 1717             while ( Gtk::Main::events_pending() )
 1718                 Gtk::Main::iteration();
 1719         }
 1720     }
 1721     else 
 1722     {   //close harddisk information
 1723         for ( int t = hpaned_main .get_position() ;  t > 0 ; t -= 15 )
 1724         {
 1725             hpaned_main .set_position( t );
 1726             while ( Gtk::Main::events_pending() )
 1727                 Gtk::Main::iteration();
 1728         }
 1729         hpaned_main .get_child1() ->hide() ;
 1730     }
 1731 }
 1732 
 1733 void Win_GParted::menu_view_operations()
 1734 {
 1735     if (static_cast<Gtk::CheckMenuItem *>(mainmenu_items[MENU_PENDING_OPERATIONS])->get_active())
 1736         open_operationslist() ;
 1737     else 
 1738         close_operationslist() ;
 1739 }
 1740 
 1741 void Win_GParted::show_disklabel_unrecognized ( Glib::ustring device_name )
 1742 {
 1743     //Display dialog box indicating that no partition table was found on the device
 1744     Gtk::MessageDialog dialog( *this,
 1745             /*TO TRANSLATORS: looks like   No partition table found on device /dev/sda */
 1746             Glib::ustring::compose( _( "No partition table found on device %1" ), device_name ),
 1747             false,
 1748             Gtk::MESSAGE_INFO,
 1749             Gtk::BUTTONS_OK,
 1750             true ) ;
 1751     Glib::ustring tmp_msg = _( "A partition table is required before partitions can be added." ) ;
 1752     tmp_msg += "\n" ;
 1753     tmp_msg += _( "To create a new partition table choose the menu item:" ) ;
 1754     tmp_msg += "\n" ;
 1755     /*TO TRANSLATORS: this message represents the menu item Create Partition Table under the Device menu. */
 1756     tmp_msg += _( "Device --> Create Partition Table." ) ;
 1757     dialog .set_secondary_text( tmp_msg ) ;
 1758     dialog .run() ;
 1759 }
 1760 
 1761 void Win_GParted::show_resize_readonly( const Glib::ustring & path )
 1762 {
 1763     Gtk::MessageDialog dialog( *this,
 1764                                /* TO TRANSLATORS: looks like   Unable to resize read-only file system /dev/sda1 */
 1765                                Glib::ustring::compose( _("Unable to resize read-only file system %1"), path ),
 1766                                false,
 1767                                Gtk::MESSAGE_INFO,
 1768                                Gtk::BUTTONS_OK,
 1769                                true );
 1770     Glib::ustring msg = _("The file system can not be resized while it is mounted read-only.");
 1771     msg += "\n";
 1772     msg += _("Either unmount the file system or remount it read-write.");
 1773     dialog.set_secondary_text( msg );
 1774     dialog.run();
 1775 }
 1776 
 1777 
 1778 void Win_GParted::show_help(const Glib::ustring & filename /* E.g., "gparted" */,
 1779                             const Glib::ustring & link_id  /* For context sensitive help */)
 1780 {
 1781     // Build uri string
 1782     Glib::ustring uri = "help:" + filename;
 1783     if (link_id.size() > 0)
 1784         uri = uri + "/" + link_id;
 1785 
 1786     // Check if yelp is available to provide a useful error message.
 1787     // Missing yelp is the most common cause of failure to display help.
 1788     //
 1789     // This early check is performed because failure of gtk_show_uri*()
 1790     // method only provides a generic "Operation not permitted" message.
 1791     if (Glib::find_program_in_path("yelp").empty())
 1792     {
 1793         Gtk::MessageDialog errorDialog(*this,
 1794                                        _("Unable to open GParted Manual help file"),
 1795                                        false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
 1796         Glib::ustring sec_text(_("Command yelp not found."));
 1797         sec_text.append("\n");
 1798         sec_text.append("\n");
 1799         sec_text.append(_("Install yelp and try again."));
 1800         errorDialog.set_secondary_text(sec_text, true);
 1801         errorDialog.run();
 1802         return;
 1803     }
 1804 
 1805     GError *error = NULL;
 1806 
 1807     // Display help window
 1808 #if HAVE_GTK_SHOW_URI_ON_WINDOW
 1809     // NULL is provided for the gtk_show_uri_on_window() parent window
 1810     // so that failures to launch yelp are reported.
 1811     // https://gitlab.gnome.org/GNOME/gparted/-/merge_requests/82#note_1106114
 1812     gtk_show_uri_on_window(NULL, uri.c_str(), gtk_get_current_event_time(), &error);
 1813 #else
 1814     GdkScreen *gscreen = gscreen = gdk_screen_get_default();
 1815     gtk_show_uri(gscreen, uri.c_str(), gtk_get_current_event_time(), &error);
 1816 #endif
 1817     if (error != NULL)
 1818     {
 1819         Gtk::MessageDialog errorDialog(*this,
 1820                                        _("Failed to open GParted Manual help file"),
 1821                                        false,
 1822                                        Gtk::MESSAGE_ERROR,
 1823                                        Gtk::BUTTONS_OK,
 1824                                        true);
 1825         errorDialog.set_secondary_text(error->message);
 1826         errorDialog.run();
 1827     }
 1828 
 1829     g_clear_error(&error);
 1830 }
 1831 
 1832 void Win_GParted::menu_help_contents()
 1833 {
 1834 #ifdef ENABLE_HELP_DOC
 1835     //GParted was built with help documentation
 1836     show_help("gparted", "");
 1837 #else
 1838     //GParted was built *without* help documentation using --disable-doc
 1839     Gtk::MessageDialog dialog( *this,
 1840             _( "Documentation is not available" ),
 1841             false,
 1842             Gtk::MESSAGE_INFO,
 1843             Gtk::BUTTONS_OK,
 1844             true ) ;
 1845     Glib::ustring tmp_msg = _( "This build of gparted is configured without documentation." ) ;
 1846     tmp_msg += "\n" ;
 1847     tmp_msg += _( "Documentation is available at the project web site." ) ;
 1848     tmp_msg += "\n" ;
 1849     tmp_msg += "https://gparted.org";
 1850     dialog .set_secondary_text( tmp_msg ) ;
 1851     dialog .set_title( _("GParted Manual") );
 1852     dialog .run() ;
 1853 #endif
 1854 }
 1855 
 1856 void Win_GParted::menu_help_about()
 1857 {
 1858     std::vector<Glib::ustring> strings ;
 1859     
 1860     Gtk::AboutDialog dialog ;
 1861     dialog .set_transient_for( *this ) ;
 1862 
 1863     dialog.set_program_name(_("GParted"));
 1864     dialog .set_logo_icon_name( "gparted" ) ;
 1865     dialog .set_version( VERSION ) ;
 1866     dialog .set_comments( _( "GNOME Partition Editor" ) ) ;
 1867     std::string names ;
 1868     names =    "Copyright © 2004-2006 Bart Hakvoort" ;
 1869     names += "\nCopyright © 2008-2021 Curtis Gedak" ;
 1870     names += "\nCopyright © 2011-2021 Mike Fleetwood" ;
 1871     dialog .set_copyright( names ) ;
 1872 
 1873     //authors
 1874     //Names listed in alphabetical order by LAST name.
 1875     //See also AUTHORS file -- names listed in opposite order to try to be fair.
 1876     strings .push_back( "Luca Bacci <luca.bacci982@gmail.com>" );
 1877     strings .push_back( "Sinlu Bes <e80f00@gmail.com>" ) ;
 1878     strings .push_back( "Luca Bruno <lucab@debian.org>" ) ;
 1879     strings .push_back( "Wrolf Courtney <wrolf@wrolf.net>" ) ;
 1880     strings .push_back( "Jérôme Dumesnil <jerome.dumesnil@gmail.com>" ) ;
 1881     strings .push_back( "Markus Elfring <elfring@users.sourceforge.net>" ) ;
 1882     strings .push_back( "Mike Fleetwood <mike.fleetwood@googlemail.com>" ) ;
 1883     strings .push_back( "Curtis Gedak <gedakc@users.sf.net>" ) ;
 1884     strings .push_back( "Matthias Gehre <m.gehre@gmx.de>" ) ;
 1885     strings .push_back( "Rogier Goossens <goossens.rogier@gmail.com>" ) ;
 1886     strings .push_back( "Bart Hakvoort <gparted@users.sf.net>" ) ;
 1887     strings .push_back( "Seth Heeren <sgheeren@gmail.com>" ) ;
 1888     strings .push_back( "Joan Lledó <joanlluislledo@gmail.com>" ) ;
 1889     strings .push_back( "Pali Rohár <pali.rohar@gmail.com>" );
 1890     strings .push_back( "Phillip Susi <psusi@cfl.rr.com>" ) ;
 1891     strings .push_back( "Antoine Viallon <antoine.viallon@gmail.com>" );
 1892     strings. push_back( "Michael Zimmermann <sigmaepsilon92@gmail.com>" ) ;
 1893     dialog .set_authors( strings ) ;
 1894     strings .clear() ;
 1895 
 1896     //artists
 1897     strings .push_back( "Sebastian Kraft <kraft.sebastian@gmail.com>" ) ;
 1898     dialog .set_artists( strings ) ;
 1899     strings .clear() ;
 1900 
 1901     /*TO TRANSLATORS: your name(s) here please, if there are more translators put newlines (\n) between the names.
 1902       It's a good idea to provide the url of your translation team as well. Thanks! */
 1903     Glib::ustring str_credits = _("translator-credits") ;
 1904     if ( str_credits != "translator-credits" )
 1905         dialog .set_translator_credits( str_credits ) ;
 1906 
 1907 
 1908     //the url is not clickable - should not invoke web browser as root
 1909     dialog.set_website_label( "https://gparted.org" );
 1910 
 1911     dialog .run() ;
 1912 }
 1913 
 1914 void Win_GParted::on_partition_selected( const Partition * partition_ptr, bool src_is_treeview )
 1915 {
 1916     selected_partition_ptr = partition_ptr;
 1917 
 1918     set_valid_operations() ;
 1919 
 1920     if ( src_is_treeview )
 1921         drawingarea_visualdisk.set_selected( partition_ptr );
 1922     else
 1923         treeview_detail.set_selected( partition_ptr );
 1924 }
 1925 
 1926 void Win_GParted::on_partition_activated() 
 1927 {
 1928     activate_info() ;
 1929 }
 1930 
 1931 void Win_GParted::on_partition_popup_menu( unsigned int button, unsigned int time ) 
 1932 {
 1933     menu_partition .popup( button, time );
 1934 }
 1935 
 1936 bool Win_GParted::max_amount_prim_reached() 
 1937 {
 1938     int primary_count = 0;
 1939     for ( unsigned int i = 0 ; i < display_partitions.size() ; i ++ )
 1940     {
 1941         if ( display_partitions[i].type == TYPE_PRIMARY || display_partitions[i].type == TYPE_EXTENDED )
 1942             primary_count ++;
 1943     }
 1944 
 1945     //Display error if user tries to create more primary partitions than the partition table can hold. 
 1946     if ( ! selected_partition_ptr->inside_extended && primary_count >= devices[current_device].max_prims )
 1947     {
 1948         Gtk::MessageDialog dialog( 
 1949             *this,
 1950             Glib::ustring::compose( ngettext( "It is not possible to create more than %1 primary partition"
 1951                                       , "It is not possible to create more than %1 primary partitions"
 1952                                       , devices[ current_device ] .max_prims
 1953                                       )
 1954                             , devices[ current_device ] .max_prims
 1955                             ),
 1956             false,
 1957             Gtk::MESSAGE_ERROR,
 1958             Gtk::BUTTONS_OK,
 1959             true ) ;
 1960         
 1961         dialog .set_secondary_text(
 1962             _( "If you want more partitions you should first create an extended partition. Such a partition can contain other partitions. Because an extended partition is also a primary partition it might be necessary to remove a primary partition first.") ) ;
 1963         
 1964         dialog .run() ;
 1965         
 1966         return true ;
 1967     }
 1968     
 1969     return false ;
 1970 }
 1971 
 1972 void Win_GParted::activate_resize()
 1973 {
 1974     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 1975     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 1976 
 1977     const Partition & selected_filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 1978     if ( selected_filesystem_ptn.busy && selected_filesystem_ptn.fs_readonly )
 1979     {
 1980         // Disallow online resizing of *all* file systems mounted read-only as
 1981         // none of them allow it, except for reiserfs.
 1982         show_resize_readonly( selected_partition_ptr->get_path() );
 1983         return;
 1984     }
 1985 
 1986     PartitionVector * display_partitions_ptr = &display_partitions;
 1987     if ( selected_partition_ptr->type == TYPE_LOGICAL )
 1988     {
 1989         int index_extended = find_extended_partition( display_partitions );
 1990         if ( index_extended >= 0 )
 1991             display_partitions_ptr = &display_partitions[index_extended].logicals;
 1992     }
 1993 
 1994     Partition * working_ptn;
 1995     const FSType fstype = selected_filesystem_ptn.fstype;
 1996     FS fs_cap = gparted_core.get_fs( fstype );
 1997     FS_Limits fs_limits = gparted_core.get_filesystem_limits( fstype, selected_filesystem_ptn );
 1998 
 1999     if (selected_partition_ptr->fstype == FS_LUKS && selected_partition_ptr->busy)
 2000     {
 2001         const FS & enc_cap = gparted_core.get_fs( FS_LUKS );
 2002 
 2003         // For an open LUKS mapping containing a file system being resized/moved
 2004         // create a plain Partition object with the equivalent usage for the
 2005         // Resize/Move dialog to work with.
 2006         working_ptn = static_cast<const PartitionLUKS *>( selected_partition_ptr )->clone_as_plain();
 2007 
 2008         // Construct common capabilities from the file system ones.
 2009         // Open LUKS encryption mapping can't be moved.
 2010         fs_cap.move = FS::NONE;
 2011         // Mask out resizing not also supported by open LUKS mapping.
 2012         if ( ! enc_cap.online_grow )
 2013         {
 2014             fs_cap.grow        = FS::NONE;
 2015             fs_cap.online_grow = FS::NONE;
 2016         }
 2017         if ( ! enc_cap.online_shrink )
 2018         {
 2019             fs_cap.shrink        = FS::NONE;
 2020             fs_cap.online_shrink = FS::NONE;
 2021         }
 2022 
 2023         // Adjust file system size limits accounting for LUKS encryption overhead.
 2024         Sector luks_header_size = static_cast<const PartitionLUKS *>( selected_partition_ptr )->get_header_size();
 2025         fs_limits.min_size = luks_header_size * working_ptn->sector_size +
 2026                              ( fs_limits.min_size < MEBIBYTE ) ? MEBIBYTE : fs_limits.min_size;
 2027         if ( fs_limits.max_size > 0 )
 2028             fs_limits.max_size += luks_header_size * working_ptn->sector_size;
 2029     }
 2030     else
 2031     {
 2032         working_ptn = selected_partition_ptr->clone();
 2033     }
 2034 
 2035     Dialog_Partition_Resize_Move dialog(devices[current_device],
 2036                                         fs_cap,
 2037                                         fs_limits,
 2038                                         *working_ptn,
 2039                                         *display_partitions_ptr);
 2040     dialog .set_transient_for( *this ) ;    
 2041 
 2042     delete working_ptn;
 2043     working_ptn = NULL;
 2044 
 2045     if (dialog.run() == Gtk::RESPONSE_OK                                           &&
 2046         ask_for_password_for_encrypted_resize_as_required(*selected_partition_ptr)   )
 2047     {
 2048         dialog .hide() ;
 2049 
 2050         // Apply resize/move from the dialog to a copy of the selected partition.
 2051         Partition * resized_ptn = selected_partition_ptr->clone();
 2052         resized_ptn->resize( dialog.Get_New_Partition() );
 2053 
 2054         // When resizing/moving a partition which already exists on the disk all
 2055         // possible operations could be pending so only try merging with the
 2056         // previous operation.
 2057         MergeType mergetype = MERGE_LAST_WITH_PREV;
 2058 
 2059         // If selected partition is NEW we simply remove the NEW operation from the list and add
 2060         // it again with the new size and position ( unless it's an EXTENDED )
 2061         if ( selected_partition_ptr->status == STAT_NEW && selected_partition_ptr->type != TYPE_EXTENDED )
 2062         {
 2063             resized_ptn->status = STAT_NEW;
 2064             // On a partition which is pending creation only resize/move and
 2065             // format operations are possible.  These operations are always
 2066             // mergeable with the pending operation which will create the
 2067             // partition.  Hence merge with any earlier operations to achieve
 2068             // this.
 2069             mergetype = MERGE_LAST_WITH_ANY;
 2070         }
 2071 
 2072         Operation * operation = new OperationResizeMove( devices[current_device],
 2073                                                          *selected_partition_ptr,
 2074                                                          *resized_ptn );
 2075         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_MENU);
 2076 
 2077         delete resized_ptn;
 2078         resized_ptn = NULL;
 2079 
 2080         // Display warning if moving a non-extended partition which already exists
 2081         // on the disk.
 2082         if ( operation->get_partition_original().status       != STAT_NEW                                    &&
 2083              operation->get_partition_original().sector_start != operation->get_partition_new().sector_start &&
 2084              operation->get_partition_original().type         != TYPE_EXTENDED                                  )
 2085         {
 2086             // Warn that move operation might break boot process
 2087             Gtk::MessageDialog dialog( *this,
 2088                                        _("Moving a partition might cause your operating system to fail to boot"),
 2089                                        false,
 2090                                        Gtk::MESSAGE_WARNING,
 2091                                        Gtk::BUTTONS_OK,
 2092                                        true );
 2093             Glib::ustring tmp_msg =
 2094                     /*TO TRANSLATORS: looks like   You queued an operation to move the start sector of partition /dev/sda3. */
 2095                     Glib::ustring::compose( _( "You have queued an operation to move the start sector of partition %1." )
 2096                                     , operation->get_partition_original().get_path() );
 2097             tmp_msg += _("  Failure to boot is most likely to occur if you move the GNU/Linux partition containing /boot, or if you move the Windows system partition C:.");
 2098             tmp_msg += "\n";
 2099             tmp_msg += _("You can learn how to repair the boot configuration in the GParted FAQ.");
 2100             tmp_msg += "\n";
 2101             tmp_msg += "https://gparted.org/faq.php";
 2102             tmp_msg += "\n\n";
 2103             tmp_msg += _("Moving a partition might take a very long time to apply.");
 2104             dialog.set_secondary_text( tmp_msg );
 2105             dialog.run();
 2106         }
 2107 
 2108         Add_Operation( devices[current_device], operation );
 2109         merge_operations( mergetype );
 2110     }
 2111 
 2112     show_operationslist() ;
 2113 }
 2114 
 2115 
 2116 bool Win_GParted::ask_for_password_for_encrypted_resize_as_required(const Partition& partition)
 2117 {
 2118     if (partition.fstype != FS_LUKS || ! partition.busy)
 2119         // Not active LUKS so won't need a password.
 2120         return true;
 2121 
 2122     LUKS_Mapping mapping = LUKS_Info::get_cache_entry(partition.get_path());
 2123     if (mapping.name.empty() || mapping.key_loc == KEYLOC_DMCrypt)
 2124         // LUKS volume key stored in crypt Device-Mapper target so won't require a
 2125         // password for encryption mapping resize.
 2126         return true;
 2127 
 2128     const char *pw = PasswordRAMStore::lookup(partition.uuid);
 2129     if (pw != NULL)
 2130         // GParted already has a password for this encryption mapping which was
 2131         // previously used successfully or tested for correctness.
 2132         //
 2133         // The password will still be correct, unless it was changed by someone
 2134         // outside GParted while running and since the last time the password was
 2135         // used.  Re-testing the password takes 2-3 seconds which would pause the
 2136         // UI after the [Resize/Move] button was pressed in the Resize/Move dialog
 2137         // but before the dialog closes.  With no trivial way to provide feedback
 2138         // that the password is being re-tested, don't spend coding effort to
 2139         // support this use case.  So just assume the known password is still
 2140         // correct and don't re-prompt when it will be correct 99.9% of the time.
 2141         return true;
 2142 
 2143     DialogPasswordEntry dialog(partition,
 2144                                /* TO TRANSLATORS: looks like   Enter LUKS passphrase to resize /dev/sda1 */
 2145                                Glib::ustring::compose(_("Enter LUKS passphrase to resize %1"),
 2146                                                       partition.get_path()));
 2147     dialog.set_transient_for(*this);
 2148     bool success = false;
 2149     do
 2150     {
 2151         if (dialog.run() != Gtk::RESPONSE_OK)
 2152             // Password dialog cancelled or closed without having confirmed
 2153             // the LUKS mapping passphrase.
 2154             return false;
 2155 
 2156         pw = dialog.get_password();
 2157         if (strlen(pw) == 0)
 2158         {
 2159             // cryptsetup won't accept a zero length password.
 2160             dialog.set_error_message("");
 2161             continue;
 2162         }
 2163 
 2164         // Test the password can open the encryption mapping.
 2165         const Glib::ustring mapping_name = Utils::generate_encryption_mapping_name(
 2166                                                    selected_partition_ptr->get_path());
 2167         Glib::ustring cmd = "cryptsetup luksOpen --test-passphrase " +
 2168                             Glib::shell_quote(partition.get_path()) + " " +
 2169                             Glib::shell_quote(mapping_name);
 2170         Glib::ustring output;
 2171         Glib::ustring error;
 2172         success = ! Utils::execute_command(cmd, pw, output, error);
 2173 
 2174         Glib::ustring message = (success) ? "" : _("LUKS encryption passphrase check failed");
 2175         dialog.set_error_message(message);
 2176     }
 2177     while (! success);
 2178 
 2179     // Save the password just entered and successfully tested on the LUKS mapping.
 2180     PasswordRAMStore::store(partition.uuid, pw);
 2181 
 2182     dialog.hide();
 2183 
 2184     return true;
 2185 }
 2186 
 2187 
 2188 void Win_GParted::activate_copy()
 2189 {
 2190     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2191     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2192 
 2193     delete copied_partition;
 2194     copied_partition = selected_partition_ptr->clone();
 2195 }
 2196 
 2197 void Win_GParted::activate_paste()
 2198 {
 2199     g_assert( copied_partition != NULL );  // Bug: Paste called without partition to copy
 2200     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2201     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2202 
 2203     // Unrecognised whole disk device (See GParted_Core::set_device_from_disk(), "unrecognized")
 2204     if (selected_partition_ptr->type   == TYPE_UNPARTITIONED &&
 2205         selected_partition_ptr->fstype == FS_UNALLOCATED       )
 2206     {
 2207         show_disklabel_unrecognized( devices [current_device ] .get_path() ) ;
 2208         return ;
 2209     }
 2210 
 2211     const Partition & copied_filesystem_ptn = copied_partition->get_filesystem_partition();
 2212 
 2213     if ( selected_partition_ptr->type == TYPE_UNALLOCATED )
 2214     {
 2215         if ( ! max_amount_prim_reached() )
 2216         {
 2217             FS_Limits fs_limits = gparted_core.get_filesystem_limits(
 2218                                                   copied_filesystem_ptn.fstype,
 2219                                                   copied_filesystem_ptn );
 2220 
 2221             // We don't want the messages, mount points or name of the source
 2222             // partition for the new partition being created.
 2223             Partition * part_temp = copied_filesystem_ptn.clone();
 2224             part_temp->clear_messages();
 2225             part_temp->clear_mountpoints();
 2226             part_temp->name.clear();
 2227 
 2228             Dialog_Partition_Copy dialog(devices[current_device],
 2229                                          gparted_core.get_fs(copied_filesystem_ptn.fstype),
 2230                                          fs_limits,
 2231                                          *selected_partition_ptr,
 2232                                          *part_temp);
 2233             delete part_temp;
 2234             part_temp = NULL;
 2235             dialog .set_transient_for( *this );
 2236         
 2237             if ( dialog .run() == Gtk::RESPONSE_OK )
 2238             {
 2239                 dialog .hide() ;
 2240 
 2241                 Operation * operation = new OperationCopy( devices[current_device],
 2242                                                            *selected_partition_ptr,
 2243                                                            dialog.Get_New_Partition(),
 2244                                                            *copied_partition );
 2245                 operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::COPY, Gtk::ICON_SIZE_MENU);
 2246 
 2247                 // When pasting into unallocated space set a temporary
 2248                 // path of "Copy of /dev/SRC" for display purposes until
 2249                 // the partition is created and the real path queried.
 2250                 OperationCopy * copy_op = static_cast<OperationCopy*>( operation );
 2251                 copy_op->get_partition_new().set_path(
 2252                         Glib::ustring::compose( _("Copy of %1"),
 2253                                           copy_op->get_partition_copied().get_path() ) );
 2254 
 2255                 Add_Operation( devices[current_device], operation );
 2256             }
 2257         }
 2258     }
 2259     else
 2260     {
 2261         const Partition & selected_filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 2262 
 2263         bool shown_dialog = false ;
 2264         // VGNAME from mount mount
 2265         if (selected_filesystem_ptn.fstype == FS_LVM2_PV       &&
 2266             ! selected_filesystem_ptn.get_mountpoint().empty()   )
 2267         {
 2268             if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_COPY ) )
 2269                 return ;
 2270             shown_dialog = true ;
 2271         }
 2272 
 2273         Partition * partition_new;
 2274         if (selected_partition_ptr->fstype == FS_LUKS && ! selected_partition_ptr->busy)
 2275         {
 2276             // Pasting into a closed LUKS encrypted partition will overwrite
 2277             // the encryption replacing it with a non-encrypted file system.
 2278             // Start with a plain Partition object instead of cloning the
 2279             // existing PartitionLUKS object containing a Partition object.
 2280             // FIXME:
 2281             // Expect to remove this case when creating and removing LUKS
 2282             // encryption is added as a separate action when full LUKS
 2283             // read-write support is implemented.
 2284             // WARNING:
 2285             // Deliberate object slicing of *selected_partition_ptr from
 2286             // PartitionLUKS to Partition.
 2287             partition_new = new Partition( *selected_partition_ptr );
 2288         }
 2289         else
 2290         {
 2291             // Pasting over a file system, either a plain file system or one
 2292             // within an open LUKS encryption mapping.  Start with a clone of
 2293             // the existing Partition object whether it be a plain Partition
 2294             // object or a PartitionLUKS object containing a Partition object.
 2295             partition_new = selected_partition_ptr->clone();
 2296         }
 2297         partition_new->alignment = ALIGN_STRICT;
 2298 
 2299         {
 2300             // Sub-block so that filesystem_ptn_new reference goes out of
 2301             // scope before partition_new pointer is deallocated.
 2302             Partition & filesystem_ptn_new = partition_new->get_filesystem_partition();
 2303             filesystem_ptn_new.fstype = copied_filesystem_ptn.fstype;
 2304             filesystem_ptn_new.set_filesystem_label( copied_filesystem_ptn.get_filesystem_label() );
 2305             filesystem_ptn_new.uuid = copied_filesystem_ptn.uuid;
 2306             Sector new_size = filesystem_ptn_new.get_sector_length();
 2307             if ( copied_filesystem_ptn.sector_usage_known() )
 2308             {
 2309                 if ( copied_filesystem_ptn.get_sector_length() == new_size )
 2310                 {
 2311                     // Pasting into same size existing partition, therefore
 2312                     // only block copy operation will be performed maintaining
 2313                     // the file system size.
 2314                     filesystem_ptn_new.set_sector_usage(
 2315                         copied_filesystem_ptn.sectors_used + copied_filesystem_ptn.sectors_unused,
 2316                         copied_filesystem_ptn.sectors_unused );
 2317                 }
 2318                 else
 2319                 {
 2320                     // Pasting into larger existing partition, therefore block
 2321                     // copy followed by file system grow operations (if
 2322                     // supported) will be performed making the file system
 2323                     // fill the partition.
 2324                     filesystem_ptn_new.set_sector_usage(
 2325                         new_size,
 2326                         new_size - copied_filesystem_ptn.sectors_used );
 2327                 }
 2328             }
 2329             else
 2330             {
 2331                 // FS usage of source is unknown so set destination usage unknown too.
 2332                 filesystem_ptn_new.set_sector_usage( -1, -1 );
 2333             }
 2334             filesystem_ptn_new.clear_messages();
 2335         }
 2336  
 2337         Operation * operation = new OperationCopy( devices[current_device],
 2338                                                    *selected_partition_ptr,
 2339                                                    *partition_new,
 2340                                                    *copied_partition );
 2341         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::COPY, Gtk::ICON_SIZE_MENU);
 2342 
 2343         delete partition_new;
 2344         partition_new = NULL;
 2345 
 2346         Add_Operation( devices[current_device], operation );
 2347 
 2348         if ( ! shown_dialog )
 2349         {
 2350             //Only warn that this paste operation will overwrite data in the existing
 2351             //  partition if not already shown the remove non-empty LVM2 PV dialog.
 2352             Gtk::MessageDialog dialog( *this
 2353                                      , _( "You have pasted into an existing partition" )
 2354                                      , false
 2355                                      , Gtk::MESSAGE_WARNING
 2356                                      , Gtk::BUTTONS_OK
 2357                                      , true
 2358                                      ) ;
 2359             dialog .set_secondary_text(
 2360                     /*TO TRANSLATORS: looks like   The data in /dev/sda3 will be lost if you apply this operation. */
 2361                     Glib::ustring::compose( _( "The data in %1 will be lost if you apply this operation." ),
 2362                     selected_partition_ptr->get_path() ) );
 2363             dialog .run() ;
 2364         }
 2365     }
 2366 
 2367     show_operationslist() ;
 2368 }
 2369 
 2370 void Win_GParted::activate_new()
 2371 {
 2372     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2373     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2374 
 2375     // Unrecognised whole disk device (See GParted_Core::set_device_from_disk(), "unrecognized")
 2376     if (selected_partition_ptr->type   == TYPE_UNPARTITIONED &&
 2377         selected_partition_ptr->fstype == FS_UNALLOCATED       )
 2378     {
 2379         show_disklabel_unrecognized( devices [current_device ] .get_path() ) ;
 2380     }
 2381     else if ( ! max_amount_prim_reached() )
 2382     {
 2383         // Check if an extended partition already exist; so that the dialog can
 2384         // decide whether to allow the creation of the only extended partition
 2385         // type or not.
 2386         bool any_extended = ( find_extended_partition( display_partitions ) >= 0 );
 2387         Dialog_Partition_New dialog( devices[current_device],
 2388                                      *selected_partition_ptr,
 2389                                      any_extended,
 2390                                      new_count,
 2391                                      gparted_core.get_filesystems() );
 2392         dialog .set_transient_for( *this );
 2393         
 2394         if ( dialog .run() == Gtk::RESPONSE_OK )
 2395         {
 2396             dialog .hide() ;
 2397             
 2398             new_count++ ;
 2399             Operation * operation = new OperationCreate( devices[current_device],
 2400                                                          *selected_partition_ptr,
 2401                                                          dialog.Get_New_Partition() );
 2402             operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU);
 2403 
 2404             Add_Operation( devices[current_device], operation );
 2405 
 2406             show_operationslist() ;
 2407         }
 2408     }
 2409 }
 2410 
 2411 void Win_GParted::activate_delete()
 2412 { 
 2413     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2414     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2415 
 2416     // VGNAME from mount mount
 2417     if (selected_partition_ptr->fstype == FS_LVM2_PV && ! selected_partition_ptr->get_mountpoint().empty())
 2418     {
 2419         if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_DELETE ) )
 2420             return ;
 2421     }
 2422 
 2423     /* since logicals are *always* numbered from 5 to <last logical> there can be a shift
 2424      * in numbers after deletion.
 2425      * e.g. consider /dev/hda5 /dev/hda6 /dev/hda7. Now after removal of /dev/hda6,
 2426      * /dev/hda7 is renumbered to /dev/hda6
 2427      * the new situation is now /dev/hda5 /dev/hda6. If /dev/hda7 was mounted 
 2428      * the OS cannot find /dev/hda7 anymore and the results aren't that pretty.
 2429      * It seems best to check for this and prohibit deletion with some explanation to the user.*/
 2430      if ( selected_partition_ptr->type             == TYPE_LOGICAL                         &&
 2431           selected_partition_ptr->status           != STAT_NEW                             &&
 2432           selected_partition_ptr->partition_number <  devices[current_device].highest_busy    )
 2433     {   
 2434         Gtk::MessageDialog dialog( *this,
 2435                                    Glib::ustring::compose( _("Unable to delete %1!"), selected_partition_ptr->get_path() ),
 2436                                    false,
 2437                                    Gtk::MESSAGE_ERROR,
 2438                                    Gtk::BUTTONS_OK,
 2439                                    true );
 2440 
 2441         dialog .set_secondary_text( 
 2442             Glib::ustring::compose( _("Please unmount any logical partitions having a number higher than %1"),
 2443                       selected_partition_ptr->partition_number ) );
 2444 
 2445         dialog .run() ;
 2446         return;
 2447     }
 2448     
 2449     //if partition is on the clipboard...(NOTE: we can't use Partition::== here..)
 2450     if ( copied_partition != NULL && selected_partition_ptr->get_path() == copied_partition->get_path() )
 2451     {
 2452         Gtk::MessageDialog dialog( *this,
 2453                                    Glib::ustring::compose( _("Are you sure you want to delete %1?"),
 2454                                                      selected_partition_ptr->get_path() ),
 2455                                    false,
 2456                                    Gtk::MESSAGE_QUESTION,
 2457                                    Gtk::BUTTONS_NONE,
 2458                                    true );
 2459 
 2460         dialog .set_secondary_text( _("After deletion this partition is no longer available for copying.") ) ;
 2461         
 2462         /*TO TRANSLATORS: dialogtitle, looks like   Delete /dev/hda2 (ntfs, 2345 MiB) */
 2463         dialog.set_title( Glib::ustring::compose( _("Delete %1 (%2, %3)"),
 2464                                             selected_partition_ptr->get_path(),
 2465                                             Utils::get_filesystem_string(selected_partition_ptr->fstype),
 2466                                             Utils::format_size( selected_partition_ptr->get_sector_length(), selected_partition_ptr->sector_size ) ) );
 2467         dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
 2468         dialog .add_button( Gtk::Stock::DELETE, Gtk::RESPONSE_OK );
 2469     
 2470         dialog .show_all_children() ;
 2471 
 2472         if ( dialog .run() != Gtk::RESPONSE_OK )
 2473             return ;
 2474 
 2475         // Deleting partition on the clipboard.  Clear clipboard.
 2476         delete copied_partition;
 2477         copied_partition = NULL;
 2478     }
 2479 
 2480     // If deleted one is NEW, it doesn't make sense to add it to the operationslist,
 2481     // we erase its creation and possible modifications like resize etc.. from the operationslist.
 2482     // Calling Refresh_Visual will wipe every memory of its existence ;-)
 2483     if ( selected_partition_ptr->status == STAT_NEW )
 2484     {
 2485         //remove all operations done on this new partition (this includes creation) 
 2486         for ( int t = 0 ; t < static_cast<int>( operations .size() ) ; t++ ) 
 2487             if ( operations[t]->type                           != OPERATION_DELETE                   &&
 2488                  operations[t]->get_partition_new().get_path() == selected_partition_ptr->get_path()    )
 2489                 remove_operation( t-- ) ;
 2490                 
 2491         //determine lowest possible new_count
 2492         new_count = 0 ; 
 2493         for ( unsigned int t = 0 ; t < operations .size() ; t++ )
 2494             if ( operations[t]->type                                 != OPERATION_DELETE &&
 2495                  operations[t]->get_partition_new().status           == STAT_NEW         &&
 2496                  operations[t]->get_partition_new().partition_number >  new_count           )
 2497                 new_count = operations[t]->get_partition_new().partition_number;
 2498             
 2499         new_count += 1 ;
 2500 
 2501         // After deleting all operations for the never applied partition creation,
 2502         // try to merge all remaining adjacent operations to catch any which are
 2503         // newly adjacent and can now be merged.  (Applies to resize/move and
 2504         // format operations on real, already existing partitions which are only
 2505         // merged when adjacent).
 2506         merge_operations( MERGE_ALL_ADJACENT );
 2507 
 2508         Refresh_Visual(); 
 2509                 
 2510         if ( ! operations .size() )
 2511             close_operationslist() ;
 2512     }
 2513     else //deletion of a real partition...
 2514     {
 2515         Operation * operation = new OperationDelete( devices[ current_device ], *selected_partition_ptr );
 2516         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU);
 2517 
 2518         Add_Operation( devices[current_device], operation );
 2519     }
 2520 
 2521     show_operationslist() ;
 2522 }
 2523 
 2524 void Win_GParted::activate_info()
 2525 {
 2526     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2527     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2528 
 2529     Dialog_Partition_Info dialog( *selected_partition_ptr );
 2530     dialog .set_transient_for( *this );
 2531     dialog .run();
 2532 }
 2533 
 2534 void Win_GParted::activate_format( FSType new_fs )
 2535 {
 2536     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2537     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2538 
 2539     const Partition & filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 2540 
 2541     // For non-empty LVM2 PV confirm overwrite before continuing.  VGNAME from mount mount.
 2542     if (filesystem_ptn.fstype == FS_LVM2_PV && ! filesystem_ptn.get_mountpoint().empty())
 2543     {
 2544         if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_FORMAT ) )
 2545             return ;
 2546     }
 2547 
 2548     // Compose Partition object to represent the format operation.
 2549     Partition * temp_ptn;
 2550     if (selected_partition_ptr->fstype == FS_LUKS && ! selected_partition_ptr->busy)
 2551     {
 2552         // Formatting a closed LUKS encrypted partition will erase the encryption
 2553         // replacing it with a non-encrypted file system.  Start with a plain
 2554         // Partition object instead of cloning the existing PartitionLUKS object
 2555         // containing a Partition object.
 2556         // FIXME:
 2557         // Expect to remove this case when creating and removing LUKS encryption
 2558         // is added as a separate action when full LUKS read-write support is
 2559         // implemented.
 2560         temp_ptn = new Partition;
 2561     }
 2562     else
 2563     {
 2564         // Formatting a file system, either a plain file system or one within an
 2565         // open LUKS encryption mapping.  Start with a clone of the existing
 2566         // Partition object whether it be a plain Partition object or a
 2567         // PartitionLUKS object containing a Partition object.
 2568         temp_ptn = selected_partition_ptr->clone();
 2569     }
 2570     {
 2571         // Sub-block so that temp_filesystem_ptn reference goes out of scope
 2572         // before temp_ptn pointer is deallocated.
 2573         Partition & temp_filesystem_ptn = temp_ptn->get_filesystem_partition();
 2574         temp_filesystem_ptn.Reset();
 2575         temp_filesystem_ptn.Set( filesystem_ptn.device_path,
 2576                                  filesystem_ptn.get_path(),
 2577                                  filesystem_ptn.partition_number,
 2578                                  filesystem_ptn.type,
 2579                                  new_fs,
 2580                                  filesystem_ptn.sector_start,
 2581                                  filesystem_ptn.sector_end,
 2582                                  filesystem_ptn.sector_size,
 2583                                  filesystem_ptn.inside_extended,
 2584                                  false );
 2585         // Leave sector usage figures as new Partition object defaults of
 2586         // -1, -1, 0 (_used, _unused, _unallocated) representing unknown.
 2587         // Also leaves fs_block_size default of -1 so that FileSystem derived
 2588         // get_filesystem_limits() call below can differentiate reformat to same
 2589         // file system case apart from resize case.
 2590     }
 2591     temp_ptn->name = selected_partition_ptr->name;
 2592     temp_ptn->status = STAT_FORMATTED;
 2593 
 2594     // Generate minimum and maximum partition size limits for the new file system.
 2595     FS_Limits fs_limits = gparted_core.get_filesystem_limits( new_fs, temp_ptn->get_filesystem_partition() );
 2596     bool encrypted = false;
 2597     if (selected_partition_ptr->fstype == FS_LUKS && selected_partition_ptr->busy)
 2598     {
 2599         encrypted = true;
 2600         // Calculate the actual overhead rather than just using the size of the
 2601         // LUKS header so that correct limits are reported in cases when the
 2602         // active LUKS mapping doesn't extend to the end of the partition for this
 2603         // format file system only operation.
 2604         Byte_Value encryption_overhead = selected_partition_ptr->get_byte_length() -
 2605                                          filesystem_ptn.get_byte_length();
 2606         fs_limits.min_size += encryption_overhead;
 2607         if ( fs_limits.max_size > 0 )
 2608             fs_limits.max_size += encryption_overhead;
 2609     }
 2610 
 2611     // Confirm partition is the right size to store the file system.
 2612     if ( ( selected_partition_ptr->get_byte_length() < fs_limits.min_size )                       ||
 2613          ( fs_limits.max_size && selected_partition_ptr->get_byte_length() > fs_limits.max_size )    )
 2614     {
 2615         Gtk::MessageDialog dialog( *this,
 2616                                    Glib::ustring::compose( /* TO TRANSLATORS: looks like
 2617                                                       * Cannot format this file system to fat16.
 2618                                                       */
 2619                                                      _("Cannot format this file system to %1"),
 2620                                                      Utils::get_filesystem_string( encrypted, new_fs ) ),
 2621                                    false,
 2622                                    Gtk::MESSAGE_ERROR,
 2623                                    Gtk::BUTTONS_OK,
 2624                                    true );
 2625 
 2626         if ( selected_partition_ptr->get_byte_length() < fs_limits.min_size )
 2627             dialog.set_secondary_text( Glib::ustring::compose(
 2628                     /* TO TRANSLATORS: looks like
 2629                      * A fat16 file system requires a partition of at least 16.00 MiB.
 2630                      */
 2631                      _( "A %1 file system requires a partition of at least %2."),
 2632                      Utils::get_filesystem_string( encrypted, new_fs ),
 2633                      Utils::format_size( fs_limits.min_size, 1 /* Byte */ ) ) );
 2634         else
 2635             dialog.set_secondary_text( Glib::ustring::compose(
 2636                     /* TO TRANSLATORS: looks like
 2637                      * A partition with a hfs file system has a maximum size of 2.00 GiB.
 2638                      */
 2639                      _( "A partition with a %1 file system has a maximum size of %2."),
 2640                      Utils::get_filesystem_string( encrypted, new_fs ),
 2641                      Utils::format_size( fs_limits.max_size, 1 /* Byte */ ) ) );
 2642 
 2643         dialog.run();
 2644     }
 2645     else
 2646     {
 2647         // When formatting a partition which already exists on the disk, all
 2648         // possible operations could be pending so only try merging with the
 2649         // previous operation.
 2650         MergeType mergetype = MERGE_LAST_WITH_PREV;
 2651 
 2652         // If selected partition is NEW we simply remove the NEW operation from
 2653         // the list and add it again with the new file system
 2654         if ( selected_partition_ptr->status == STAT_NEW )
 2655         {
 2656             temp_ptn->status = STAT_NEW;
 2657             // On a partition which is pending creation only resize/move and
 2658             // format operations are possible.  These operations are always
 2659             // mergeable with the pending operation which will create the
 2660             // partition.  Hence merge with any earlier operations to achieve
 2661             // this.
 2662             mergetype = MERGE_LAST_WITH_ANY;
 2663         }
 2664 
 2665         Operation * operation = new OperationFormat( devices[current_device],
 2666                                                      *selected_partition_ptr,
 2667                                                      *temp_ptn );
 2668         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::CONVERT, Gtk::ICON_SIZE_MENU);
 2669 
 2670         Add_Operation( devices[current_device], operation );
 2671         merge_operations( mergetype );
 2672 
 2673         show_operationslist();
 2674     }
 2675 
 2676     delete temp_ptn;
 2677     temp_ptn = NULL;
 2678 }
 2679 
 2680 bool Win_GParted::open_encrypted_partition( const Partition & partition,
 2681                                             const char * entered_password,
 2682                                             Glib::ustring & message )
 2683 {
 2684     const char * pw = NULL;
 2685     if ( entered_password == NULL )
 2686     {
 2687         pw = PasswordRAMStore::lookup( partition.uuid );
 2688         if ( pw == NULL )
 2689         {
 2690             // Internal documentation message never shown to user.
 2691             message = "No stored password available";
 2692             return false;
 2693         }
 2694     }
 2695     else
 2696     {
 2697         pw = entered_password;
 2698         if ( strlen( pw ) == 0 )
 2699         {
 2700             // "cryptsetup" won't accept a zero length password.
 2701             message = "";
 2702             return false;
 2703         }
 2704     }
 2705 
 2706     const Glib::ustring mapping_name = Utils::generate_encryption_mapping_name(selected_partition_ptr->get_path());
 2707     Glib::ustring cmd = "cryptsetup luksOpen " +
 2708                         Glib::shell_quote( partition.get_path() ) + " " +
 2709                         Glib::shell_quote( mapping_name );
 2710 
 2711     show_pulsebar( Glib::ustring::compose( _("Opening encryption on %1"), partition.get_path() ) );
 2712     Glib::ustring output;
 2713     Glib::ustring error;
 2714     bool success = ! Utils::execute_command( cmd, pw, output, error );
 2715     hide_pulsebar();
 2716     if ( success && pw != NULL )
 2717         // Save the password just entered and successfully used to open the LUKS
 2718         // mapping.
 2719         PasswordRAMStore::store( partition.uuid, pw );
 2720     else if ( ! success )
 2721         // Erase the password used during for the failure to open the LUKS
 2722         // mapping.
 2723         PasswordRAMStore::erase( partition.uuid );
 2724 
 2725     message = ( success ) ? "" : _("Failed to open LUKS encryption");
 2726     return success;
 2727 }
 2728 
 2729 void Win_GParted::toggle_crypt_busy_state()
 2730 {
 2731     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2732     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2733 
 2734     enum Action
 2735     {
 2736         NONE      = 0,
 2737         LUKSCLOSE = 1,
 2738         LUKSOPEN  = 2
 2739     };
 2740     Action action = NONE;
 2741     Glib::ustring disallowed_msg;
 2742     Glib::ustring pulse_msg;
 2743     Glib::ustring failure_msg;
 2744     if ( selected_partition_ptr->busy )
 2745     {
 2746         action = LUKSCLOSE;
 2747         disallowed_msg = _("The close encryption action cannot be performed when there are operations pending for the partition.");
 2748         pulse_msg = Glib::ustring::compose( _("Closing encryption on %1"), selected_partition_ptr->get_path() );
 2749         failure_msg = _("Could not close encryption");
 2750     }
 2751     else  // ( ! selected_partition_ptr->busy )
 2752     {
 2753         action = LUKSOPEN;
 2754         disallowed_msg = _("The open encryption action cannot be performed when there are operations pending for the partition.");
 2755     }
 2756 
 2757     if ( ! check_toggle_busy_allowed( disallowed_msg ) )
 2758         // One or more operations are pending for this partition so changing the
 2759         // busy state is not allowed.
 2760         //
 2761         // After set_valid_operations() has allowed the operations to be queued
 2762         // the rest of the code assumes the busy state of the partition won't
 2763         // change.  Therefore pending operations must prevent changing the busy
 2764         // state of the partition.
 2765         return;
 2766 
 2767     bool success = false;
 2768     Glib::ustring cmd;
 2769     Glib::ustring output;
 2770     Glib::ustring error;
 2771     Glib::ustring error_msg;
 2772     switch ( action )
 2773     {
 2774         case LUKSCLOSE:
 2775             cmd = "cryptsetup luksClose " +
 2776                   Glib::shell_quote( selected_partition_ptr->get_mountpoint() );
 2777             show_pulsebar( pulse_msg );
 2778             success = ! Utils::execute_command( cmd, output, error );
 2779             hide_pulsebar();
 2780             error_msg = "<i># " + cmd + "\n" + error + "</i>";
 2781             break;
 2782         case LUKSOPEN:
 2783         {
 2784             // Attempt to unlock LUKS using stored passphrase first.
 2785             success = open_encrypted_partition( *selected_partition_ptr, NULL, error_msg );
 2786             if ( success )
 2787                 break;
 2788 
 2789             // Open password dialog and attempt to unlock LUKS mapping.
 2790             DialogPasswordEntry dialog(*selected_partition_ptr,
 2791                                        /* TO TRANSLATORS: looks like
 2792                             * Enter LUKS passphrase to open /dev/sda1
 2793                             */
 2794                                        Glib::ustring::compose(_("Enter LUKS passphrase to open %1"),
 2795                                                               selected_partition_ptr->get_path()));
 2796             dialog.set_transient_for( *this );
 2797             do
 2798             {
 2799                 if ( dialog.run() != Gtk::RESPONSE_OK )
 2800                     // Password dialog cancelled or closed without the
 2801                     // LUKS mapping having been opened.  Skip refresh.
 2802                     return;
 2803 
 2804                 success = open_encrypted_partition( *selected_partition_ptr,
 2805                                                     dialog.get_password(),
 2806                                                     error_msg );
 2807                 dialog.set_error_message( error_msg );
 2808             } while ( ! success );
 2809         }
 2810         default:
 2811             // Impossible
 2812             break;
 2813     }
 2814 
 2815     if ( ! success )
 2816         show_toggle_failure_dialog( failure_msg, error_msg );
 2817 
 2818     menu_gparted_refresh_devices();
 2819 }
 2820 
 2821 bool Win_GParted::unmount_partition( const Partition & partition, Glib::ustring & error )
 2822 {
 2823     const std::vector<Glib::ustring> fs_mountpoints = partition.get_mountpoints();
 2824     const std::vector<Glib::ustring> all_mountpoints = Mount_Info::get_all_mountpoints();
 2825 
 2826     std::vector<Glib::ustring> skipped_mountpoints;
 2827     std::vector<Glib::ustring> umount_errors;
 2828 
 2829     for ( unsigned int i = 0 ; i < fs_mountpoints.size() ; i ++ )
 2830     {
 2831         if ( std::count( all_mountpoints.begin(), all_mountpoints.end(), fs_mountpoints[i] ) >= 2 )
 2832         {
 2833             // This mount point has two or more different file systems mounted
 2834             // on top of each other.  Refuse to unmount it as in the general
 2835             // case all have to be unmounted and then all except the file
 2836             // system being unmounted have to be remounted.  This is too rare
 2837             // a case to write such complicated code for.
 2838             skipped_mountpoints.push_back( fs_mountpoints[i] );
 2839         }
 2840         else
 2841         {
 2842             Glib::ustring cmd = "umount -v " + Glib::shell_quote( fs_mountpoints[i] );
 2843             Glib::ustring dummy;
 2844             Glib::ustring umount_error;
 2845             if ( Utils::execute_command( cmd, dummy, umount_error ) )
 2846                 umount_errors.push_back( "# " + cmd + "\n" + umount_error );
 2847         }
 2848     }
 2849 
 2850     if ( umount_errors.size() > 0 )
 2851     {
 2852         error = "<i>" + Glib::build_path( "</i>\n<i>", umount_errors ) + "</i>";
 2853         return false;
 2854     }
 2855     if ( skipped_mountpoints.size() > 0 )
 2856     {
 2857         error = _("The partition could not be unmounted from the following mount points:");
 2858         error += "\n\n<i>" + Glib::build_path( "\n", skipped_mountpoints ) + "</i>\n\n";
 2859         error += _("This is because other partitions are also mounted on these mount points.  You are advised to unmount them manually.");
 2860         return false;
 2861     }
 2862     return true;
 2863 }
 2864 
 2865 bool Win_GParted::check_toggle_busy_allowed( const Glib::ustring & disallowed_msg )
 2866 {
 2867     int operation_count = partition_in_operation_queue_count( *selected_partition_ptr );
 2868     if ( operation_count > 0 )
 2869     {
 2870         Glib::ustring primary_msg = Glib::ustring::compose(
 2871             /* TO TRANSLATORS: Singular case looks like   1 operation is currently pending for partition /dev/sdb1 */
 2872             ngettext( "%1 operation is currently pending for partition %2",
 2873             /* TO TRANSLATORS: Plural case looks like   3 operations are currently pending for partition /dev/sdb1 */
 2874                       "%1 operations are currently pending for partition %2",
 2875                       operation_count ),
 2876             operation_count,
 2877             selected_partition_ptr->get_path() );
 2878 
 2879         Gtk::MessageDialog dialog( *this,
 2880                                    primary_msg,
 2881                                    false,
 2882                                    Gtk::MESSAGE_INFO,
 2883                                    Gtk::BUTTONS_OK,
 2884                                    true );
 2885 
 2886         Glib::ustring secondary_msg = disallowed_msg + "\n" +
 2887             _("Use the Edit menu to undo, clear or apply pending operations.");
 2888         dialog.set_secondary_text( secondary_msg );
 2889         dialog.run();
 2890         return false;
 2891     }
 2892     return true;
 2893 }
 2894 
 2895 void Win_GParted::show_toggle_failure_dialog( const Glib::ustring & failure_summary,
 2896                                               const Glib::ustring & marked_up_error )
 2897 {
 2898     Gtk::MessageDialog dialog( *this,
 2899                                failure_summary,
 2900                                false,
 2901                                Gtk::MESSAGE_ERROR,
 2902                                Gtk::BUTTONS_OK,
 2903                                true );
 2904     dialog.set_secondary_text( marked_up_error, true );
 2905     dialog.run();
 2906 }
 2907 
 2908 void Win_GParted::toggle_fs_busy_state()
 2909 {
 2910     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 2911     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 2912 
 2913     enum Action
 2914     {
 2915         NONE          = 0,
 2916         SWAPOFF       = 1,
 2917         SWAPON        = 2,
 2918         DEACTIVATE_VG = 3,
 2919         ACTIVATE_VG   = 4,
 2920         UNMOUNT       = 5
 2921     };
 2922     Action action = NONE;
 2923     Glib::ustring disallowed_msg;
 2924     Glib::ustring pulse_msg;
 2925     Glib::ustring failure_msg;
 2926     const Partition & filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 2927     if (filesystem_ptn.fstype == FS_LINUX_SWAP && filesystem_ptn.busy)
 2928     {
 2929         action = SWAPOFF;
 2930         disallowed_msg = _("The swapoff action cannot be performed when there are operations pending for the partition.");
 2931         pulse_msg = Glib::ustring::compose( _("Deactivating swap on %1"), filesystem_ptn.get_path() );
 2932         failure_msg = _("Could not deactivate swap");
 2933     }
 2934     else if (filesystem_ptn.fstype == FS_LINUX_SWAP && ! filesystem_ptn.busy)
 2935     {
 2936         action = SWAPON;
 2937         disallowed_msg = _("The swapon action cannot be performed when there are operations pending for the partition.");
 2938         pulse_msg = Glib::ustring::compose( _("Activating swap on %1"), filesystem_ptn.get_path() );
 2939         failure_msg = _("Could not activate swap");
 2940     }
 2941     else if (filesystem_ptn.fstype == FS_LVM2_PV && filesystem_ptn.busy)
 2942     {
 2943         action = DEACTIVATE_VG;
 2944         disallowed_msg = _("The deactivate Volume Group action cannot be performed when there are operations pending for the partition.");
 2945         pulse_msg = Glib::ustring::compose( _("Deactivating Volume Group %1"),
 2946                                       filesystem_ptn.get_mountpoint() );  // VGNAME from point point
 2947         failure_msg = _("Could not deactivate Volume Group");
 2948     }
 2949     else if (filesystem_ptn.fstype == FS_LVM2_PV && ! filesystem_ptn.busy)
 2950     {
 2951         action = ACTIVATE_VG;
 2952         disallowed_msg = _("The activate Volume Group action cannot be performed when there are operations pending for the partition.");
 2953         pulse_msg = Glib::ustring::compose( _("Activating Volume Group %1"),
 2954                                       filesystem_ptn.get_mountpoint() );  // VGNAME from point point
 2955         failure_msg = _("Could not activate Volume Group");
 2956     }
 2957     else if ( filesystem_ptn.busy )
 2958     {
 2959         action = UNMOUNT;
 2960         disallowed_msg = _("The unmount action cannot be performed when there are operations pending for the partition.");
 2961         pulse_msg = Glib::ustring::compose( _("Unmounting %1"), filesystem_ptn.get_path() );
 2962         failure_msg = Glib::ustring::compose( _("Could not unmount %1"), filesystem_ptn.get_path() );
 2963     }
 2964     else
 2965         // Impossible.  Mounting a file system calls activate_mount_partition().
 2966         return;
 2967 
 2968     if ( ! check_toggle_busy_allowed( disallowed_msg ) )
 2969         // One or more operations are pending for this partition so changing the
 2970         // busy state is not allowed.
 2971         //
 2972         // After set_valid_operations() has allowed the operations to be queued
 2973         // the rest of the code assumes the busy state of the partition won't
 2974         // change.  Therefore pending operations must prevent changing the busy
 2975         // state of the partition.
 2976         return;
 2977 
 2978     show_pulsebar( pulse_msg );
 2979     bool success = false;
 2980     Glib::ustring cmd;
 2981     Glib::ustring output;
 2982     Glib::ustring error;
 2983     Glib::ustring error_msg;
 2984     switch ( action )
 2985     {
 2986         case SWAPOFF:
 2987             cmd = "swapoff -v " + Glib::shell_quote( filesystem_ptn.get_path() );
 2988             success = ! Utils::execute_command( cmd, output, error );
 2989             error_msg = "<i># " + cmd + "\n" + error + "</i>";
 2990             break;
 2991         case SWAPON:
 2992             cmd = "swapon -v " + Glib::shell_quote( filesystem_ptn.get_path() );
 2993             success = ! Utils::execute_command( cmd, output, error );
 2994             error_msg = "<i># " + cmd + "\n" + error + "</i>";
 2995             break;
 2996         case DEACTIVATE_VG:
 2997             cmd = "lvm vgchange -a n " + Glib::shell_quote( filesystem_ptn.get_mountpoint() );
 2998             success = ! Utils::execute_command( cmd, output, error );
 2999             error_msg = "<i># " + cmd + "\n" + error + "</i>";
 3000             break;
 3001         case ACTIVATE_VG:
 3002             cmd = "lvm vgchange -a y " + Glib::shell_quote( filesystem_ptn.get_mountpoint() );
 3003             success = ! Utils::execute_command( cmd, output, error );
 3004             error_msg = "<i># " + cmd + "\n" + error + "</i>";
 3005             break;
 3006         case UNMOUNT:
 3007             success = unmount_partition( filesystem_ptn, error_msg );
 3008             break;
 3009         default:
 3010             // Impossible
 3011             break;
 3012     }
 3013     hide_pulsebar();
 3014 
 3015     if ( ! success )
 3016         show_toggle_failure_dialog( failure_msg, error_msg );
 3017 
 3018     menu_gparted_refresh_devices() ;
 3019 }
 3020 
 3021 void Win_GParted::activate_mount_partition( unsigned int index ) 
 3022 {
 3023     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3024     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3025 
 3026     Glib::ustring disallowed_msg = _("The mount action cannot be performed when an operation is pending for the partition.");
 3027     if ( ! check_toggle_busy_allowed( disallowed_msg ) )
 3028         // One or more operations are pending for this partition so changing the
 3029         // busy state by mounting the file system is not allowed.
 3030         return;
 3031 
 3032     bool success;
 3033     Glib::ustring cmd;
 3034     Glib::ustring output;
 3035     Glib::ustring error;
 3036     Glib::ustring error_msg;
 3037 
 3038     const Partition & filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 3039     show_pulsebar( Glib::ustring::compose( _("mounting %1 on %2"),
 3040                                      filesystem_ptn.get_path(),
 3041                                      filesystem_ptn.get_mountpoints()[index] ) );
 3042 
 3043     // First try mounting letting mount (libblkid) determine the file system type.
 3044     cmd = "mount -v " + Glib::shell_quote( filesystem_ptn.get_path() ) +
 3045           " " + Glib::shell_quote( filesystem_ptn.get_mountpoints()[index] );
 3046     success = ! Utils::execute_command( cmd, output, error );
 3047     if ( ! success )
 3048     {
 3049         error_msg = "<i># " + cmd + "\n" + error + "</i>";
 3050 
 3051         Glib::ustring type = Utils::get_filesystem_kernel_name(filesystem_ptn.fstype);
 3052         if ( ! type.empty() )
 3053         {
 3054             // Second try mounting specifying the GParted determined file
 3055             // system type.
 3056             cmd = "mount -v -t " + Glib::shell_quote( type ) +
 3057                   " " + Glib::shell_quote( filesystem_ptn.get_path() ) +
 3058                   " " + Glib::shell_quote( filesystem_ptn.get_mountpoints()[index] );
 3059             success = ! Utils::execute_command( cmd, output, error );
 3060             if ( ! success )
 3061                 error_msg += "\n<i># " + cmd + "\n" + error + "</i>";
 3062         }
 3063     }
 3064     hide_pulsebar();
 3065     if ( ! success )
 3066     {
 3067         Glib::ustring failure_msg = Glib::ustring::compose( _("Could not mount %1 on %2"),
 3068                                                       filesystem_ptn.get_path(),
 3069                                                       filesystem_ptn.get_mountpoints()[index] );
 3070         show_toggle_failure_dialog( failure_msg, error_msg );
 3071     }
 3072 
 3073     menu_gparted_refresh_devices() ;
 3074 }
 3075 
 3076 void Win_GParted::activate_disklabel()
 3077 {
 3078     //If there are active mounted partitions on the device then warn
 3079     //  the user that all partitions must be unactive before creating
 3080     //  a new partition table
 3081     int active_count = active_partitions_on_device_count( devices[ current_device ] ) ;
 3082     if ( active_count > 0 )
 3083     {
 3084         Glib::ustring tmp_msg =
 3085             Glib::ustring::compose( /*TO TRANSLATORS: Singular case looks like  1 partition is currently active on device /dev/sda */
 3086                               ngettext( "%1 partition is currently active on device %2"
 3087                               /*TO TRANSLATORS: Plural case looks like    3 partitions are currently active on device /dev/sda */
 3088                                       , "%1 partitions are currently active on device %2"
 3089                                       , active_count
 3090                                       )
 3091                             , active_count
 3092                             , devices[ current_device ] .get_path()
 3093                             ) ;
 3094         Gtk::MessageDialog dialog( *this
 3095                                  , tmp_msg
 3096                                  , false
 3097                                  , Gtk::MESSAGE_INFO
 3098                                  , Gtk::BUTTONS_OK
 3099                                  , true
 3100                                  ) ;
 3101         tmp_msg  = _( "A new partition table cannot be created when there are active partitions." ) ;
 3102         tmp_msg += "  " ;
 3103         tmp_msg += _( "Active partitions are those that are in use, such as a mounted file system, or enabled swap space." ) ;
 3104         tmp_msg += "\n" ;
 3105         tmp_msg += _( "Use Partition menu options, such as unmount or swapoff, to deactivate all partitions on this device before creating a new partition table." ) ;
 3106         dialog .set_secondary_text( tmp_msg ) ;
 3107         dialog .run() ;
 3108         return ;
 3109     }
 3110 
 3111     //If there are pending operations then warn the user that these
 3112     //  operations must either be applied or cleared before creating
 3113     //  a new partition table.
 3114     if ( operations .size() )
 3115     {
 3116         Glib::ustring tmp_msg =
 3117             Glib::ustring::compose( ngettext( "%1 operation is currently pending"
 3118                                       , "%1 operations are currently pending"
 3119                                       , operations .size()
 3120                                       )
 3121                             , operations .size()
 3122                             ) ;
 3123         Gtk::MessageDialog dialog( *this
 3124                                  , tmp_msg
 3125                                  , false
 3126                                  , Gtk::MESSAGE_INFO
 3127                                  , Gtk::BUTTONS_OK
 3128                                  , true
 3129                                  ) ;
 3130         tmp_msg  = _( "A new partition table cannot be created when there are pending operations." ) ;
 3131         tmp_msg += "\n" ;
 3132         tmp_msg += _( "Use the Edit menu to either clear or apply all operations before creating a new partition table." ) ;
 3133         dialog .set_secondary_text( tmp_msg ) ;
 3134         dialog .run() ;
 3135         return ;
 3136     }
 3137 
 3138     //Display dialog for creating a new partition table.
 3139     Dialog_Disklabel dialog( devices[ current_device ] ) ;
 3140     dialog .set_transient_for( *this );
 3141 
 3142     if ( dialog .run() == Gtk::RESPONSE_APPLY )
 3143     {
 3144         if ( ! gparted_core.set_disklabel( devices[current_device], dialog.Get_Disklabel() ) )
 3145         {
 3146             Gtk::MessageDialog dialog( *this,
 3147                            _("Error while creating partition table"),
 3148                            true,
 3149                            Gtk::MESSAGE_ERROR,
 3150                            Gtk::BUTTONS_OK,
 3151                            true ) ;
 3152             dialog .run() ;
 3153         }
 3154 
 3155         dialog .hide() ;
 3156             
 3157         menu_gparted_refresh_devices() ;
 3158     }
 3159 }
 3160 
 3161 //Runs when the Device->Attempt Rescue Data is clicked
 3162 void Win_GParted::activate_attempt_rescue_data()
 3163 {
 3164     if(Glib::find_program_in_path( "gpart" ) .empty()) //Gpart must be installed to continue
 3165     {
 3166         Gtk::MessageDialog errorDialog(*this, "", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
 3167         errorDialog.set_message(_("Command gpart was not found"));
 3168         errorDialog.set_secondary_text(_("This feature uses gpart. Please install gpart and try again."));
 3169 
 3170         errorDialog.run();
 3171 
 3172         return;
 3173     }
 3174 
 3175     //Dialog information
 3176     Glib::ustring sec_text = _( "A full disk scan is needed to find file systems." ) ;
 3177     sec_text += "\n" ;
 3178     sec_text +=_("The scan might take a very long time.");
 3179     sec_text += "\n" ;
 3180     sec_text += _("After the scan you can mount any discovered file systems and copy the data to other media.") ;
 3181     sec_text += "\n" ;
 3182     sec_text += _("Do you want to continue?");
 3183 
 3184     Gtk::MessageDialog messageDialog(*this, "", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true);
 3185     /*TO TRANSLATORS: looks like    Search for file systems on /deb/sdb */
 3186     messageDialog.set_message(Glib::ustring::compose(_("Search for file systems on %1"), devices[ current_device ] .get_path()));
 3187     messageDialog.set_secondary_text(sec_text);
 3188 
 3189     if(messageDialog.run()!=Gtk::RESPONSE_OK)
 3190     {
 3191         return;
 3192     }
 3193 
 3194     messageDialog.hide();
 3195 
 3196     /*TO TRANSLATORS: looks like    Searching for file systems on /deb/sdb */
 3197     show_pulsebar(Glib::ustring::compose( _("Searching for file systems on %1"), devices[ current_device ] .get_path()));
 3198     Glib::ustring gpart_output;
 3199     gparted_core.guess_partition_table(devices[ current_device ], gpart_output);
 3200     hide_pulsebar();
 3201     Dialog_Rescue_Data dialog;
 3202     dialog .set_transient_for( *this );
 3203 
 3204     //Reads the output of gpart
 3205     dialog.init_partitions( &devices[current_device], gpart_output );
 3206 
 3207     if ( ! dialog.found_partitions() )
 3208     {
 3209         //Dialog information
 3210         Gtk::MessageDialog errorDialog(*this, "", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
 3211         
 3212         /*TO TRANSLATORS: looks like    No file systems found on /deb/sdb */
 3213         errorDialog.set_message(Glib::ustring::compose(_("No file systems found on %1"), devices[ current_device ] .get_path()));
 3214         errorDialog.set_secondary_text(_("The disk scan by gpart did not find any recognizable file systems on this disk."));
 3215 
 3216         errorDialog.run();
 3217         return;
 3218     }
 3219 
 3220     dialog.run();
 3221     dialog.hide();
 3222 
 3223     Utils::execute_command( "umount /tmp/gparted-roview*" );
 3224 
 3225     menu_gparted_refresh_devices() ;
 3226 }
 3227 
 3228 void Win_GParted::activate_manage_flags() 
 3229 {
 3230     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3231     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3232 
 3233     get_window()->set_cursor(Gdk::Cursor::create(Gdk::WATCH));
 3234     while ( Gtk::Main::events_pending() )
 3235         Gtk::Main::iteration() ;
 3236 
 3237     DialogManageFlags dialog( *selected_partition_ptr, gparted_core.get_available_flags( *selected_partition_ptr ) );
 3238     dialog .set_transient_for( *this ) ;
 3239     dialog .signal_get_flags .connect(
 3240         sigc::mem_fun( &gparted_core, &GParted_Core::get_available_flags ) ) ;
 3241     dialog .signal_toggle_flag .connect(
 3242         sigc::mem_fun( &gparted_core, &GParted_Core::toggle_flag ) ) ;
 3243 
 3244     get_window() ->set_cursor() ;
 3245     
 3246     dialog .run() ;
 3247     dialog .hide() ;
 3248     
 3249     if ( dialog .any_change )
 3250         menu_gparted_refresh_devices() ;
 3251 }
 3252 
 3253 
 3254 void Win_GParted::activate_check() 
 3255 {
 3256     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3257     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3258 
 3259     if (! ask_for_password_for_encrypted_resize_as_required(*selected_partition_ptr))
 3260         // Open encryption mapping needing a passphrase to resize but the password
 3261         // dialog was cancelled or closed without providing a working passphrase.
 3262         return;
 3263 
 3264     // FIXME: Consider constructing new partition object with zero unallocated and
 3265     // messages cleared to represent how applying a check operation also grows the
 3266     // file system to fill the partition.
 3267     Operation * operation = new OperationCheck( devices[current_device], *selected_partition_ptr );
 3268 
 3269     operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU);
 3270 
 3271     Add_Operation( devices[current_device], operation );
 3272     // Try to merge this check operation with all previous operations.
 3273     merge_operations( MERGE_LAST_WITH_ANY );
 3274 
 3275     show_operationslist() ;
 3276 }
 3277 
 3278 void Win_GParted::activate_label_filesystem()
 3279 {
 3280     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3281     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3282 
 3283     const Partition & filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 3284     Dialog_FileSystem_Label dialog( filesystem_ptn );
 3285     dialog .set_transient_for( *this );
 3286 
 3287     if (    dialog .run() == Gtk::RESPONSE_OK
 3288          && dialog.get_new_label() != filesystem_ptn.get_filesystem_label() )
 3289     {
 3290         dialog .hide() ;
 3291         // Make a duplicate of the selected partition (used in UNDO)
 3292         Partition * part_temp = selected_partition_ptr->clone();
 3293 
 3294         part_temp->get_filesystem_partition().set_filesystem_label( dialog.get_new_label() );
 3295 
 3296         Operation * operation = new OperationLabelFileSystem( devices[current_device],
 3297                                                               *selected_partition_ptr, *part_temp );
 3298         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU);
 3299 
 3300         delete part_temp;
 3301         part_temp = NULL;
 3302 
 3303         Add_Operation( devices[current_device], operation );
 3304         // Try to merge this label file system operation with all previous
 3305         // operations.
 3306         merge_operations( MERGE_LAST_WITH_ANY );
 3307 
 3308         show_operationslist() ;
 3309     }
 3310 }
 3311 
 3312 void Win_GParted::activate_name_partition()
 3313 {
 3314     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3315     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3316 
 3317     Dialog_Partition_Name dialog( *selected_partition_ptr,
 3318                                   devices[current_device].get_max_partition_name_length() );
 3319     dialog.set_transient_for( *this );
 3320 
 3321     if (    dialog.run() == Gtk::RESPONSE_OK
 3322          && dialog.get_new_name() != selected_partition_ptr->name )
 3323     {
 3324         dialog.hide();
 3325         // Make a duplicate of the selected partition (used in UNDO)
 3326         Partition * part_temp = selected_partition_ptr->clone();
 3327 
 3328         part_temp->name = dialog.get_new_name();
 3329 
 3330         Operation * operation = new OperationNamePartition( devices[current_device],
 3331                                                             *selected_partition_ptr, *part_temp );
 3332         operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU);
 3333 
 3334         delete part_temp;
 3335         part_temp = NULL;
 3336 
 3337         Add_Operation( devices[current_device], operation );
 3338         // Try to merge this name partition operation with all previous
 3339         // operations.
 3340         merge_operations( MERGE_LAST_WITH_ANY );
 3341 
 3342         show_operationslist();
 3343     }
 3344 }
 3345 
 3346 void Win_GParted::activate_change_uuid()
 3347 {
 3348     g_assert( selected_partition_ptr != NULL );  // Bug: Partition callback without a selected partition
 3349     g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object
 3350 
 3351     const Partition & filesystem_ptn = selected_partition_ptr->get_filesystem_partition();
 3352     const FileSystem *filesystem_object = gparted_core.get_filesystem_object(filesystem_ptn.fstype);
 3353     if ( filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING ) != "" )
 3354     {
 3355         int i ;
 3356         Gtk::MessageDialog dialog( *this,
 3357                                    filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, 0 ),
 3358                                    false,
 3359                                    Gtk::MESSAGE_WARNING,
 3360                                    Gtk::BUTTONS_OK,
 3361                                    true );
 3362         Glib::ustring tmp_msg = "" ;
 3363         for ( i = 1 ; filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, i ) != "" ; i++ )
 3364         {
 3365             if ( i > 1 )
 3366                 tmp_msg += "\n\n" ;
 3367             tmp_msg += filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, i );
 3368         }
 3369         dialog .set_secondary_text( tmp_msg ) ;
 3370         dialog .run() ;
 3371     }
 3372 
 3373     // Make a duplicate of the selected partition (used in UNDO)
 3374     Partition * temp_ptn = selected_partition_ptr->clone();
 3375 
 3376     {
 3377         // Sub-block so that temp_filesystem_ptn reference goes out of scope
 3378         // before temp_ptn pointer is deallocated.
 3379         Partition & temp_filesystem_ptn = temp_ptn->get_filesystem_partition();
 3380         if (temp_filesystem_ptn.fstype == FS_NTFS)
 3381             // Explicitly ask for half, so that the user will be aware of it
 3382             // Also, keep this kind of policy out of the NTFS code.
 3383             temp_filesystem_ptn.uuid = UUID_RANDOM_NTFS_HALF;
 3384         else
 3385             temp_filesystem_ptn.uuid = UUID_RANDOM;
 3386     }
 3387 
 3388     Operation * operation = new OperationChangeUUID( devices[current_device],
 3389                                                      *selected_partition_ptr, *temp_ptn );
 3390     operation->icon = Utils::mk_pixbuf(*this, Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU);
 3391 
 3392     delete temp_ptn;
 3393     temp_ptn = NULL;
 3394 
 3395     Add_Operation( devices[current_device], operation );
 3396     // Try to merge this change UUID operation with all previous operations.
 3397     merge_operations( MERGE_LAST_WITH_ANY );
 3398 
 3399     show_operationslist() ;
 3400 }
 3401 
 3402 void Win_GParted::activate_undo()
 3403 {
 3404     //when undoing a creation it's safe to decrease the newcount by one
 3405     if ( operations .back() ->type == OPERATION_CREATE )
 3406         new_count-- ;
 3407 
 3408     remove_operation() ;        
 3409     
 3410     Refresh_Visual();
 3411     
 3412     if ( ! operations .size() )
 3413         close_operationslist() ;
 3414 
 3415     //FIXME:  A slight flicker may be introduced by this extra display refresh.
 3416     //An extra display refresh seems to prevent the disk area visual disk from
 3417     //  disappearing when there enough operations to require a scrollbar
 3418     //  (about 4+ operations with default window size) and a user clicks on undo.
 3419     //  See also Win_GParted::Add_operation().
 3420     drawingarea_visualdisk .queue_draw() ;
 3421 }
 3422 
 3423 void Win_GParted::remove_operation( int index, bool remove_all ) 
 3424 {
 3425     if ( remove_all )
 3426     {
 3427         for ( unsigned int t = 0 ; t < operations .size() ; t++ )
 3428             delete operations[ t ] ;
 3429 
 3430         operations .clear() ;
 3431     }
 3432     else if ( index == -1  && operations .size() > 0 )
 3433     {
 3434         delete operations .back() ;
 3435         operations .pop_back() ;
 3436     }
 3437     else if ( index > -1 && index < static_cast<int>( operations .size() ) )
 3438     {
 3439         delete operations[ index ] ;
 3440         operations .erase( operations .begin() + index ) ;
 3441     }
 3442 }
 3443 
 3444 int Win_GParted::partition_in_operation_queue_count( const Partition & partition )
 3445 {
 3446     int operation_count = 0 ;
 3447 
 3448     for ( unsigned int t = 0 ; t < operations .size() ; t++ )
 3449     {
 3450         if ( partition.get_path() == operations[t]->get_partition_original().get_path() )
 3451             operation_count++ ;
 3452     }
 3453 
 3454     return operation_count ;
 3455 }
 3456 
 3457 int  Win_GParted::active_partitions_on_device_count( const Device & device )
 3458 {
 3459     int active_count = 0 ;
 3460 
 3461     //Count the active partitions on the device
 3462     for ( unsigned int k=0; k < device .partitions .size(); k++ )
 3463     {
 3464         // Count the active primary and extended partitions
 3465         if (   device .partitions[ k ] .busy
 3466             && device .partitions[ k ] .type != TYPE_UNALLOCATED
 3467            )
 3468             active_count++ ;
 3469 
 3470         //Count the active logical partitions
 3471         if (   device .partitions[ k ] .busy
 3472             && device .partitions[ k ] .type == TYPE_EXTENDED
 3473            )
 3474         {
 3475             for ( unsigned int j=0; j < device .partitions[ k ] .logicals .size(); j++ )
 3476             {
 3477                 if (   device .partitions[ k ] .logicals [ j ] .busy
 3478                     && device .partitions[ k ] .logicals [ j ] .type != TYPE_UNALLOCATED
 3479                    )
 3480                     active_count++ ;
 3481             }
 3482         }
 3483     }
 3484 
 3485     return active_count ;
 3486 }
 3487 
 3488 void Win_GParted::activate_apply()
 3489 {
 3490     Gtk::MessageDialog dialog( *this,
 3491                    _("Are you sure you want to apply the pending operations?"),
 3492                    false,
 3493                    Gtk::MESSAGE_WARNING,
 3494                    Gtk::BUTTONS_NONE,
 3495                    true );
 3496     Glib::ustring temp;
 3497     temp =  _( "Editing partitions has the potential to cause LOSS of DATA.") ;
 3498     temp += "\n" ;
 3499     temp += _( "You are advised to backup your data before proceeding." ) ;
 3500     dialog .set_secondary_text( temp ) ;
 3501     dialog .set_title( _( "Apply operations to device" ) );
 3502     
 3503     dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
 3504     dialog .add_button( Gtk::Stock::APPLY, Gtk::RESPONSE_OK );
 3505     
 3506     dialog .show_all_children() ;
 3507     if ( dialog.run() == Gtk::RESPONSE_OK )
 3508     {
 3509         dialog .hide() ; //hide confirmationdialog
 3510 
 3511         Dialog_Progress dialog_progress(devices, operations);
 3512         dialog_progress .set_transient_for( *this ) ;
 3513         dialog_progress .signal_apply_operation .connect(
 3514             sigc::mem_fun(gparted_core, &GParted_Core::apply_operation_to_disk) ) ;
 3515  
 3516         int response ;
 3517         do
 3518         {
 3519             response = dialog_progress .run() ;
 3520         }
 3521         while ( response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_OK ) ;
 3522         
 3523         dialog_progress .hide() ;
 3524         
 3525         //wipe operations...
 3526         remove_operation( -1, true ) ;
 3527         hbox_operations .clear() ;
 3528         close_operationslist() ;
 3529                             
 3530         //reset new_count to 1
 3531         new_count = 1 ;
 3532         
 3533         //reread devices and their layouts...
 3534         menu_gparted_refresh_devices() ;
 3535     }
 3536 }
 3537 
 3538 bool Win_GParted::remove_non_empty_lvm2_pv_dialog( const OperationType optype )
 3539 {
 3540     Glib::ustring tmp_msg ;
 3541     switch ( optype )
 3542     {
 3543         case OPERATION_DELETE:
 3544             tmp_msg = Glib::ustring::compose( _( "You are deleting non-empty LVM2 Physical Volume %1" ),
 3545                                         selected_partition_ptr->get_path() );
 3546             break ;
 3547         case OPERATION_FORMAT:
 3548             tmp_msg = Glib::ustring::compose( _( "You are formatting over non-empty LVM2 Physical Volume %1" ),
 3549                                         selected_partition_ptr->get_path() );
 3550             break ;
 3551         case OPERATION_COPY:
 3552             tmp_msg = Glib::ustring::compose( _( "You are pasting over non-empty LVM2 Physical Volume %1" ),
 3553                                         selected_partition_ptr->get_path() );
 3554             break ;
 3555         default:
 3556             break ;
 3557     }
 3558     Gtk::MessageDialog dialog( *this, tmp_msg,
 3559                                false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true ) ;
 3560 
 3561     tmp_msg =  _( "Deleting or overwriting the Physical Volume is irrecoverable and will destroy or damage the "
 3562                   " Volume Group." ) ;
 3563     tmp_msg += "\n\n" ;
 3564     tmp_msg += _( "To avoid destroying or damaging the Volume Group, you are advised to cancel and use external "
 3565                   "LVM commands to free the Physical Volume before attempting this operation." ) ;
 3566     tmp_msg += "\n\n" ;
 3567     tmp_msg += _( "Do you want to continue to forcibly delete the Physical Volume?" ) ;
 3568 
 3569     Glib::ustring vgname = LVM2_PV_Info::get_vg_name( selected_partition_ptr->get_path() );
 3570     std::vector<Glib::ustring> members ;
 3571     if ( ! vgname .empty() )
 3572         members = LVM2_PV_Info::get_vg_members( vgname );
 3573 
 3574     //Single copy of each string for translation purposes
 3575     const Glib::ustring vgname_label  = _( "Volume Group:" ) ;
 3576     const Glib::ustring members_label = _( "Members:" ) ;
 3577 
 3578     dialog .set_secondary_text( tmp_msg, true ) ;
 3579 
 3580     // Nicely formatted display of VG members by using a grid below the secondary
 3581     // text in the dialog.
 3582     Gtk::Box * msg_area = dialog .get_message_area() ;
 3583 
 3584     Gtk::Separator *hsep(manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)));
 3585     msg_area ->pack_start( * hsep ) ;
 3586 
 3587     Gtk::Grid *grid(manage(new Gtk::Grid()));
 3588     grid->set_column_spacing(10);
 3589     msg_area->pack_start(*grid);
 3590 
 3591     // Volume Group
 3592     grid->attach(*Utils::mk_label("<b>" + Glib::ustring(vgname_label) + "</b>"),
 3593                  0, 0, 1, 1);
 3594     grid->attach(*Utils::mk_label(vgname, true, false, true),
 3595                  1, 0, 1, 1);
 3596 
 3597     // Members
 3598     grid->attach(*Utils::mk_label("<b>" + Glib::ustring(members_label) + "</b>",
 3599                                   true, false, false, Gtk::ALIGN_START),
 3600                  0, 1, 1, 1);
 3601 
 3602     Glib::ustring members_str = "" ;
 3603     if ( ! members .empty() )
 3604     {
 3605         for ( unsigned int i = 0 ; i < members .size() ; i ++ )
 3606         {
 3607             if ( i > 0 )
 3608                 members_str += "\n" ;
 3609             members_str += members[i] ;
 3610         }
 3611     }
 3612     grid->attach(*Utils::mk_label(members_str, true, false, true, Gtk::ALIGN_START),
 3613                  1, 1, 1, 1);
 3614 
 3615     dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
 3616     dialog .add_button( Gtk::Stock::DELETE, Gtk::RESPONSE_OK );
 3617     dialog .show_all() ;
 3618     if ( dialog .run() == Gtk::RESPONSE_OK )
 3619         return true ;
 3620     return false ;
 3621 }
 3622 
 3623 } // GParted