def __init__(self, parent, delete_event_cb):
     """Prepare the processes dialog"""
     self.on_window_processes_delete_event = delete_event_cb
     self.processes = {}
     self.poller_id = None
     # Load the user interface
     self.ui = GtkBuilderLoader(get_ui_file('processes.glade'))
     # Restore the saved size and position
     settings.positions.restore_window_position(
         self.ui.window_processes, SECTION_WINDOW_NAME)
     # Initialize actions
     for widget in self.ui.get_objects_by_type(Gtk.Action):
         # Connect the actions accelerators
         widget.connect_accelerator()
         # Set labels
         widget.set_label(text(widget.get_label()))
     # Initialize tooltips
     for widget in self.ui.get_objects_by_type(Gtk.ToolButton):
         action = widget.get_related_action()
         if action:
             widget.set_tooltip_text(action.get_label().replace('_', ''))
     self.model = ModelProcesses(self.ui.store_processes)
     # Connect signals from the glade file to the module functions
     self.ui.connect_signals(self)
class UIProcesses(object):
    def __init__(self, parent, delete_event_cb):
        """Prepare the processes dialog"""
        self.on_window_processes_delete_event = delete_event_cb
        self.processes = {}
        self.poller_id = None
        # Load the user interface
        self.ui = GtkBuilderLoader(get_ui_file('processes.glade'))
        # Restore the saved size and position
        settings.positions.restore_window_position(
            self.ui.window_processes, SECTION_WINDOW_NAME)
        # Initialize actions
        for widget in self.ui.get_objects_by_type(Gtk.Action):
            # Connect the actions accelerators
            widget.connect_accelerator()
            # Set labels
            widget.set_label(text(widget.get_label()))
        # Initialize tooltips
        for widget in self.ui.get_objects_by_type(Gtk.ToolButton):
            action = widget.get_related_action()
            if action:
                widget.set_tooltip_text(action.get_label().replace('_', ''))
        self.model = ModelProcesses(self.ui.store_processes)
        # Connect signals from the glade file to the module functions
        self.ui.connect_signals(self)

    def show(self):
        """Show the processes dialog"""
        settings.positions.restore_window_position(
            self.ui.window_processes, SECTION_WINDOW_NAME)
        self.ui.window_processes.show()

    def hide(self):
        """Hide the processes dialog"""
        settings.positions.save_window_position(
            self.ui.window_processes, SECTION_WINDOW_NAME)
        self.ui.window_processes.hide()

    def destroy(self):
        """Destroy the Debug dialog"""
        self.hide()
        self.ui.window_processes.destroy()
        self.ui.window_processes = None

    def add_process(self, host, destination, service, command):
        """Add a new process"""
        process = subprocess.Popen(args=get_list_from_string_list(command),
                                   shell=False)
        treeiter = self.model.add_data(ProcessInfo(host,
                                                   destination,
                                                   service,
                                                   process))
        # Enable process actions
        self.ui.actions_processes.set_sensitive(True)
        # Save process for further polling
        self.processes[self.model.get_key(treeiter)] = process
        self.model.add_detail(treeiter,
                              _('Process started'),
                              'media-playback-start')
        self.start_polling()

    def poll_processes(self):
        """Poll each process to check if it was terminated"""
        for key in self.processes.keys():
            process = self.processes[key]
            return_code = process.poll()
            # Has the process exited?
            if return_code is not None:
                treeiter = self.model.get_iter(key)
                self.model.add_detail(treeiter,
                                      _('Exit code: %d') % return_code,
                                      'media-playback-stop')
                # Remove the completed process
                self.processes.pop(key)
        if len(self.processes):
            # Continue the polling
            return True
        else:
            # Stop the polling
            self.poller_id = None
            return False

    def start_polling(self):
        """Start the poller timeout if it wasn't already started"""
        if not self.poller_id:
            self.poller_id = GLib.timeout_add(1000, self.poll_processes)

    def on_action_process_activate(self, action):
        """Execute an action for the selected process"""
        selected_row = get_treeview_selected_row(self.ui.tvw_processes)
        if selected_row:
            iter_parent = self.model.model.iter_parent(selected_row)
            selected_path = self.model.model[selected_row].path
            # Get the path of the process
            if iter_parent is None:
                tree_path = self.model.model[selected_row].path
            else:
                tree_path = self.model.model[iter_parent].path
            #
            selected_key = self.model.get_key(tree_path)
            if selected_key in self.processes:
                selected_process = self.processes[selected_key]
                treeiter = self.model.get_iter(selected_key)
                if action is self.ui.action_kill:
                    # Resume the process and terminate it
                    selected_process.send_signal(subprocess.signal.SIGCONT)
                    selected_process.terminate()
                    debug.add_info(
                        _('The process with the PID %d was terminated') % (
                            selected_process.pid))
                    self.model.add_detail(treeiter,
                                          _('Process terminated'),
                                          'media-playback-stop')
                elif action is self.ui.action_pause:
                    # Pause the process by sending the STOP signal
                    selected_process.send_signal(subprocess.signal.SIGSTOP)
                    debug.add_info(
                        _('The process with the PID %d was paused') % (
                            selected_process.pid))
                    self.model.add_detail(treeiter,
                                          _('Process paused'),
                                          'media-playback-pause')
                elif action is self.ui.action_resume:
                    # Pause the process by sending the CONT signal
                    selected_process.send_signal(subprocess.signal.SIGCONT)
                    debug.add_info(
                        _('The process with the PID %d was resumed') % (
                            selected_process.pid))
                    self.model.add_detail(treeiter,
                                          _('Process resumed'),
                                          'media-playback-start')

    def on_tvw_processes_row_activated(self, widget, treepath, column):
        """Expand or collapse the selected row"""
        selected_row = get_treeview_selected_row(self.ui.tvw_processes)
        if selected_row:
            iter_parent = self.ui.store_processes.iter_parent(selected_row)
            selected_path = self.model.model[selected_row].path
            # Get the path of the process
            if iter_parent is None:
                tree_path = self.model.model[selected_row].path
                expanded = self.ui.tvw_processes.row_expanded(tree_path)
                if expanded:
                    self.ui.tvw_processes.collapse_row(tree_path)
                else:
                    self.ui.tvw_processes.expand_row(tree_path, True)

    def on_tvw_processes_key_press_event(self, widget, event):
        """Expand and collapse nodes with keyboard arrows"""
        selected_row = get_treeview_selected_row(self.ui.tvw_processes)
        if selected_row and event.keyval in (Gdk.KEY_Left, Gdk.KEY_Right):
            iter_parent = self.ui.store_processes.iter_parent(selected_row)
            if selected_row and iter_parent is None:
                tree_path = self.model.get_path(selected_row)
                expanded = self.ui.tvw_processes.row_expanded(tree_path)
                if event.keyval == Gdk.KEY_Left and expanded:
                    # Collapse the selected node
                    self.ui.tvw_processes.collapse_row(tree_path)
                elif event.keyval == Gdk.KEY_Right and not expanded:
                    # Expand the selected node
                    self.ui.tvw_processes.expand_row(tree_path, False)
        elif event.keyval == Gdk.KEY_Menu:
            # Show popup menu on Menu key press
            event = Gdk.EventButton()
            event.type = Gdk.EventType.BUTTON_RELEASE
            event.button = Gdk.BUTTON_SECONDARY
            self.ui.tvw_processes.event(event)

    def on_tvw_processes_button_release_event(self, widget, event):
        """Show processes popup menu on right click"""
        if event.button == Gdk.BUTTON_SECONDARY:
            show_popup_menu(self.ui.menu_popup, event.button)