gparted/include/Win_GParted.h

282 lines
8.8 KiB
C
Raw Normal View History

/* Copyright (C) 2004 Bart
* Copyright (C) 2008, 2009, 2010 Curtis Gedak
2004-09-19 14:24:53 -06:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
2004-09-19 14:24:53 -06:00
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
2004-09-19 14:24:53 -06:00
*/
#ifndef GPARTED_WIN_GPARTED_H
#define GPARTED_WIN_GPARTED_H
2004-09-19 14:24:53 -06:00
#include "../include/Device.h"
#include "../include/DrawingAreaVisualDisk.h"
2004-09-19 14:24:53 -06:00
#include "../include/Partition.h"
#include "../include/TreeView_Detail.h"
#include "../include/GParted_Core.h"
#include "../include/HBoxOperations.h"
2004-09-19 14:24:53 -06:00
#include <sigc++/class_slot.h>
#include <gtkmm/paned.h>
#include <gtkmm/toolbar.h>
#include <gtkmm/separatortoolitem.h>
#include <gtkmm/menubar.h>
#include <gtkmm/statusbar.h>
#include <gtkmm/combobox.h>
#include <gtkmm/progressbar.h>
#include <gtkmm/window.h>
#include <gtkmm/table.h>
2004-09-19 14:24:53 -06:00
namespace GParted
{
enum MergeType
{
MERGE_LAST_WITH_PREV = 0,
MERGE_LAST_WITH_ANY = 1,
MERGE_ALL_ADJACENT = 2
};
2004-09-19 14:24:53 -06:00
class Win_GParted : public Gtk::Window
{
public:
Win_GParted( const std::vector<Glib::ustring> & user_devices ) ;
2004-09-19 14:24:53 -06:00
private:
void init_menubar() ;
void init_toolbar() ;
void init_partition_menu() ;
Gtk::Menu * create_format_menu() ;
void create_format_menu_add_item( FILESYSTEM filesystem, bool activate ) ;
void init_device_info() ;
void init_hpaned_main() ;
2004-09-19 14:24:53 -06:00
void refresh_combo_devices() ;
void show_pulsebar( const Glib::ustring & status_message ) ;
void hide_pulsebar();
2004-09-19 14:24:53 -06:00
//Fill txtview_device_info_buffer with some information about the selected device
void Fill_Label_Device_Info( bool clear = false );
2004-09-19 14:24:53 -06:00
void Add_Operation( Operation * operation );
bool merge_two_operations( unsigned int first, unsigned int second );
void merge_operations( MergeType mergetype );
void Refresh_Visual();
bool valid_display_partition_ptr( const Partition * partition_ptr );
bool Quit_Check_Operations();
void set_valid_operations() ;
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
void show_operationslist() ;
2004-09-19 14:24:53 -06:00
//convenience functions
void toggle_item( bool state, int menu_item, int toolbar_item = -1 )
{
if ( menu_item >= 0 && menu_item < static_cast<int>( menu_partition .items() .size() ) )
menu_partition .items()[ menu_item ] .set_sensitive( state ) ;
if ( toolbar_item >= 0 && toolbar_item < toolbar_main .get_n_items() )
toolbar_main .get_nth_item( toolbar_item ) ->set_sensitive( state ) ;
}
void allow_new( bool state ) {
toggle_item( state, MENU_NEW, TOOLBAR_NEW ) ; }
void allow_delete( bool state ) {
toggle_item( state, MENU_DEL, TOOLBAR_DEL ) ; }
void allow_resize( bool state ) {
toggle_item( state, MENU_RESIZE_MOVE, TOOLBAR_RESIZE_MOVE ) ; }
void allow_copy( bool state ) {
toggle_item( state, MENU_COPY, TOOLBAR_COPY ) ; }
void allow_paste( bool state ) {
toggle_item( state, MENU_PASTE, TOOLBAR_PASTE ) ; }
void allow_format( bool state ) {
toggle_item( state, MENU_FORMAT ) ; }
void allow_toggle_busy_state( bool state ) {
toggle_item( state, MENU_TOGGLE_BUSY ) ; }
void allow_manage_flags( bool state ) {
toggle_item( state, MENU_FLAGS ) ; }
void allow_check( bool state ) {
toggle_item( state, MENU_CHECK ) ; }
void allow_label_filesystem( bool state ) {
toggle_item( state, MENU_LABEL_PARTITION ) ; }
void allow_name_partition( bool state ) {
toggle_item( state, MENU_NAME_PARTITION ); }
void allow_change_uuid( bool state ) {
toggle_item( state, MENU_CHANGE_UUID ) ; }
void allow_info( bool state ) {
toggle_item( state, MENU_INFO ) ; }
void allow_undo_clear_apply( bool state )
{
toggle_item( state, -1, TOOLBAR_UNDO ) ;
static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 1 ] .get_submenu() ->items()[ 0 ] )
->set_sensitive( state ) ;
static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 1 ] .get_submenu() ->items()[ 1 ] )
->set_sensitive( state ) ;
toggle_item( state, -1, TOOLBAR_APPLY ) ;
static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 1 ] .get_submenu() ->items()[ 2 ] )
->set_sensitive( state ) ;
}
//threads..
void unmount_partition( bool * succes, Glib::ustring * error );
2004-09-19 14:24:53 -06:00
//signal handlers
void open_operationslist() ;
void close_operationslist() ;
void clear_operationslist() ;
void combo_devices_changed();
void radio_devices_changed( unsigned int item ) ;
bool on_delete_event( GdkEventAny* ) ;
void on_show() ;
2004-09-27 14:12:47 -06:00
void menu_gparted_refresh_devices();
void menu_gparted_features();
void menu_gparted_quit();
void menu_view_harddisk_info();
void menu_view_operations();
void show_disklabel_unrecognized( Glib::ustring device_name );
void show_help_dialog( const Glib::ustring & filename, const Glib::ustring & link_id );
void menu_help_contents();
void menu_help_about();
2004-09-19 14:24:53 -06:00
void on_partition_selected( const Partition * partition_ptr, bool src_is_treeview );
void on_partition_activated() ;
void on_partition_popup_menu( unsigned int button, unsigned int time ) ;
bool max_amount_prim_reached() ;
2004-09-19 14:24:53 -06:00
void activate_resize();
void activate_copy();
void activate_paste();
void activate_new();
void activate_delete();
void activate_info();
void activate_format( GParted::FILESYSTEM new_fs );
void toggle_busy_state() ;
void activate_mount_partition( unsigned int index ) ;
void activate_disklabel() ;
void activate_attempt_rescue_data();
void activate_manage_flags() ;
void activate_check() ;
void activate_change_uuid() ;
void activate_label_filesystem();
void activate_name_partition();
void activate_undo();
void remove_operation( int index = -1, bool remove_all = false ) ;
int partition_in_operation_queue_count( const Partition & partition ) ;
int active_partitions_on_device_count( const Device & device ) ;
void activate_apply();
bool remove_non_empty_lvm2_pv_dialog( const OperationType optype ) ;
2004-09-19 14:24:53 -06:00
//private variables
unsigned int current_device ;
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
std::vector<Partition> display_partitions; // Copy of current device's partitions with any pending
// operations applied, as currently being shown in the GUI.
const Partition * selected_partition_ptr; // Pointer to the selected partition. (Alias to element
// in Win_GParted::display_partitions[] vector).
Partition copied_partition;
std::vector<Device> devices;
std::vector<Operation *> operations;
2004-09-19 14:24:53 -06:00
//gui stuff
Gtk::HPaned hpaned_main;
Gtk::VPaned vpaned_main;
Gtk::VBox vbox_main,vbox_info ;
Gtk::HBox hbox_toolbar, *hbox;
2004-09-19 14:24:53 -06:00
Gtk::Toolbar toolbar_main;
Gtk::MenuBar menubar_main;
Gtk::ComboBox combo_devices ;
Gtk::Menu menu_partition, *menu ;
2004-09-19 14:24:53 -06:00
Gtk::ToolButton *toolbutton;
Gtk::Statusbar statusbar;
Gtk::Image *image ;
Gtk::ScrolledWindow *scrollwindow;
Gtk::Label label_device_info1, label_device_info2, *label;
Gtk::Tooltips tooltips ;
Gtk::Table *table ;
Gtk::MenuItem *menu_item;
Gtk::ProgressBar pulsebar ;
Gtk::TreeRow treerow;
2004-09-19 14:24:53 -06:00
DrawingAreaVisualDisk drawingarea_visualdisk ;
2004-09-19 14:24:53 -06:00
TreeView_Detail treeview_detail;
HBoxOperations hbox_operations ;
//device combo
Glib::RefPtr<Gtk::ListStore> liststore_devices ;
Prevent flashing redraw of the devices combobox (#696149) The device combobox was getting drawn blank, then getting drawn again with the selected device. This was happening because at the start of Win_GParted::refresh_combo_devices() the GTK model behind the combobox, liststore_devices, was cleared, changing the active item, causing the combobox to get redrawn empty. After the GTK model had been repopulated the active item was reset causing the comboxbox to get redrawn again, now showing the selected device. Call flow: Win_GParted::refresh_combo_devices() liststore_devices->clear() //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... ... combo_devices.set_active(current_device); //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... This has always been the case, since the device combobox was first added to GParted before version 0.1 by commit: 3a4b43e0adb3974dea656fcbe90d5e191e0e9784 replaced deprecated OptionMenu with ComboBox ... Fix by temporarily blocking the devices comboxbox from emitting signal_changed while the GTK model behind the combobox is recreated. However, since automatic selection of the largest free space was added [1] in GParted 0.15.0, a more noticeable flashing redraw issue was caused in which the partition graphic and partition list were both drawn blank then redrawn fully populated. Some distributions were not affected by this at all, some only experienced a single flash and others suffered from two or more flashing redraws. Some affected distributions: CentOS 5.10, 6.5, 7.0, Debian 6, Fedora 14, 19, 20, Ubuntu 13.10, Xubuntu 14.04 LTS. Did not occur on Kubuntu 12.04 LTS. [1] 5b53c12f6ee12312a9bacb44b8b05b12a540d3d6 Select largest unallocated partition by default (#667365) Bug #696149 - Double refresh of display introduced with default unallocated space
2014-08-22 04:35:39 -06:00
sigc::connection combo_devices_changed_connection;
struct treeview_devices_Columns : public Gtk::TreeModelColumnRecord
{
Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> > icon ;
Gtk::TreeModelColumn<Glib::ustring> device ;
Gtk::TreeModelColumn<Glib::ustring> size ;
treeview_devices_Columns()
{
add( icon ) ;
add( device ) ;
add( size ) ;
}
};
treeview_devices_Columns treeview_devices_columns ;
2004-09-19 14:24:53 -06:00
//indices for partitionmenu and toolbar
int
MENU_NEW, TOOLBAR_NEW,
MENU_DEL, TOOLBAR_DEL,
MENU_RESIZE_MOVE, TOOLBAR_RESIZE_MOVE,
MENU_COPY, TOOLBAR_COPY,
MENU_PASTE, TOOLBAR_PASTE,
MENU_FORMAT,
MENU_TOGGLE_BUSY,
MENU_MOUNT,
MENU_NAME_PARTITION,
MENU_FLAGS,
MENU_CHECK,
MENU_LABEL_PARTITION,
MENU_CHANGE_UUID,
MENU_INFO,
TOOLBAR_UNDO,
TOOLBAR_APPLY ;
2004-09-19 14:24:53 -06:00
//usefull variables which are used by many different functions...
unsigned short new_count;//new_count keeps track of the new created partitions
FS fs ;
bool OPERATIONSLIST_OPEN ;
Glib::ustring gpart_output;//Output of gpart command
GParted_Core gparted_core ;
std::vector<Gtk::Label *> device_info ;
//stuff for progress overview and pulsebar
bool pulsebar_pulse();
sigc::connection pulsetimer;
2004-09-19 14:24:53 -06:00
};
} //GParted
#endif /* GPARTED_WIN_GPARTED_H */