00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 import sys
00032
00033 from dbus.server import Server
00034 from .plugin_handler import PluginHandler
00035 from .plugin_handler_dbus_service import PluginHandlerDBusService
00036 from python_qt_binding import QT_BINDING
00037 from python_qt_binding.QtCore import qDebug, QProcess, QSignalMapper, Qt, qWarning
00038 from python_qt_binding.QtGui import QToolBar, QX11EmbedContainer
00039 from .main import Main
00040 from .settings_proxy_dbus_service import SettingsProxyDBusService
00041
00042
00043 class PluginHandlerXEmbedContainer(PluginHandler):
00044
00045 """
00046 Server part of the `PluginHandlerXEmbed`.
00047 It starts the plugin in a subprocess and provides the `PluginHandlerDBusService` through a peer-to-peer DBus connection.
00048 """
00049
00050 _serial_number = 0
00051
00052 def __init__(self, parent, main_window, instance_id, application_context, container_manager, argv, dbus_object_path):
00053 super(PluginHandlerXEmbedContainer, self).__init__(parent, main_window, instance_id, application_context, container_manager, argv)
00054 self.setObjectName('PluginHandlerXEmbedContainer')
00055
00056 self._dbus_object_path = dbus_object_path
00057 self._dbus_server = None
00058 self._dbus_container_service = None
00059 self._dbus_plugin_settings_service = None
00060 self._dbus_instance_settings_service = None
00061
00062 self._process = None
00063 self._pid = None
00064
00065 self._embed_containers = {}
00066
00067 self._embed_toolbars = {}
00068 self._signal_mapper_toolbars = QSignalMapper(self)
00069 self._signal_mapper_toolbars.mapped[str].connect(self._on_toolbar_orientation_changed)
00070
00071 def _load(self):
00072 self._dbus_server = Server('tcp:bind=*')
00073 self._dbus_server.on_connection_added.append(self._add_dbus_connection)
00074 self._dbus_container_service = PluginHandlerDBusService(self, self._dbus_object_path)
00075 self._dbus_plugin_settings_service = SettingsProxyDBusService(self._dbus_object_path + '/plugin')
00076 self._dbus_instance_settings_service = SettingsProxyDBusService(self._dbus_object_path + '/instance')
00077
00078 self._process = QProcess(self)
00079 self._process.setProcessChannelMode(QProcess.SeparateChannels)
00080 self._process.readyReadStandardOutput.connect(self._print_process_output)
00081 self._process.readyReadStandardError.connect(self._print_process_error)
00082 self._process.finished.connect(self._emit_close_plugin)
00083
00084 cmd = sys.executable + ' -u'
00085 cmd += ' %s' % Main.main_filename
00086 cmd += ' --qt-binding=%s' % QT_BINDING
00087 cmd += ' --embed-plugin=%s --embed-plugin-serial=%s --embed-plugin-address=%s' % (self.instance_id().plugin_id, self.instance_id().serial_number, self._dbus_server.address)
00088 if self.argv():
00089 cmd += ' --args %s' % ' '.join(self.argv())
00090
00091 self._process.start(cmd)
00092 started = self._process.waitForStarted(3000)
00093 if not started:
00094 self._dbus_container_service.remove_from_connection()
00095 self._dbus_plugin_settings_service.remove_from_connection()
00096 self._dbus_instance_settings_service.remove_from_connection()
00097 raise RuntimeError('PluginHandlerXEmbedContainer._load() could not start subprocess in reasonable time')
00098
00099 if hasattr(self._process, 'pid'):
00100 self._pid = self._process.pid()
00101 else:
00102
00103 self.__class__._serial_number = self._serial_number + 1
00104 self._pid = self._serial_number
00105
00106 qDebug('PluginHandlerXEmbedContainer._load() started subprocess (#%s) for plugin "%s"' % (self._pid, str(self._instance_id)))
00107
00108
00109 def _add_dbus_connection(self, conn):
00110 self._dbus_container_service.add_to_connection(conn, self._dbus_object_path)
00111 self._dbus_plugin_settings_service.add_to_connection(conn, self._dbus_object_path + '/plugin')
00112 self._dbus_instance_settings_service.add_to_connection(conn, self._dbus_object_path + '/instance')
00113
00114 def _print_process_output(self):
00115 self._print_process(self._process.readAllStandardOutput(), qDebug)
00116
00117 def _print_process_error(self):
00118 self._print_process(self._process.readAllStandardError(), qWarning)
00119
00120 def _print_process(self, data, method):
00121
00122 lines = str(data).split('\n')
00123 if lines[-1] == '':
00124 lines.pop()
00125 for line in lines:
00126 method(' %d %s' % (self._pid, line))
00127
00128 def load_completed(self, loaded, has_configuration):
00129
00130 exception = None if loaded else True
00131 self._plugin_has_configuration = has_configuration
00132 self._update_title_bars()
00133 self._emit_load_completed(exception)
00134
00135 def _shutdown_plugin(self):
00136 qDebug('PluginHandlerXEmbedContainer._shutdown_plugin()')
00137 self._process.finished.disconnect(self._emit_close_plugin)
00138 self._dbus_container_service.shutdown_plugin()
00139
00140 def emit_shutdown_plugin_completed(self):
00141 self._dbus_container_service.remove_from_connection()
00142 self._dbus_plugin_settings_service.remove_from_connection()
00143 self._dbus_instance_settings_service.remove_from_connection()
00144
00145 self._process.close()
00146 self._process.waitForFinished(5000)
00147 if self._process.state() != QProcess.NotRunning:
00148 self._process.kill()
00149 self._process = None
00150
00151 super(PluginHandlerXEmbedContainer, self).emit_shutdown_plugin_completed()
00152
00153 def _unload(self):
00154 qDebug('PluginHandlerXEmbedContainer._unload()')
00155 self._emit_unload_completed()
00156
00157 def _save_settings(self, plugin_settings, instance_settings):
00158 qDebug('PluginHandlerXEmbedContainer._save_settings()')
00159 self._dbus_plugin_settings_service.set_settings(plugin_settings)
00160 self._dbus_instance_settings_service.set_settings(instance_settings)
00161 self._dbus_container_service.save_settings()
00162
00163 def emit_save_settings_completed(self):
00164 self._dbus_plugin_settings_service.set_settings(None)
00165 self._dbus_instance_settings_service.set_settings(None)
00166 super(PluginHandlerXEmbedContainer, self).emit_save_settings_completed()
00167
00168 def _restore_settings(self, plugin_settings, instance_settings):
00169 qDebug('PluginHandlerXEmbedContainer._restore_settings()')
00170 self._dbus_plugin_settings_service.set_settings(plugin_settings)
00171 self._dbus_instance_settings_service.set_settings(instance_settings)
00172 self._dbus_container_service.restore_settings()
00173
00174 def emit_restore_settings_completed(self):
00175 self._dbus_plugin_settings_service.set_settings(None)
00176 self._dbus_instance_settings_service.set_settings(None)
00177 super(PluginHandlerXEmbedContainer, self).emit_restore_settings_completed()
00178
00179 def _trigger_configuration(self):
00180 self._dbus_container_service.trigger_configuration()
00181
00182 def embed_widget(self, pid, widget_object_name):
00183 dock_widget = self._create_dock_widget()
00184 embed_container = QX11EmbedContainer(dock_widget)
00185
00186 self._add_dock_widget(dock_widget, embed_container)
00187
00188 self._embed_containers[widget_object_name] = embed_container
00189 return embed_container.winId()
00190
00191 def update_embedded_widget_title(self, widget_object_name, title):
00192 embed_container = self._embed_containers[widget_object_name]
00193 embed_container.setWindowTitle(title)
00194
00195 def unembed_widget(self, widget_object_name):
00196 embed_container = self._embed_containers[widget_object_name]
00197 self.remove_widget(embed_container)
00198 del self._embed_containers[widget_object_name]
00199
00200 def embed_toolbar(self, pid, toolbar_object_name):
00201 toolbar = QToolBar()
00202 toolbar.setObjectName(toolbar_object_name)
00203 embed_container = QX11EmbedContainer(toolbar)
00204 toolbar.addWidget(embed_container)
00205
00206 self._add_toolbar(toolbar)
00207 self._embed_containers[toolbar_object_name] = embed_container
00208
00209 self._embed_toolbars[toolbar_object_name] = toolbar
00210 self._signal_mapper_toolbars.setMapping(toolbar, toolbar_object_name)
00211 toolbar.orientationChanged.connect(self._signal_mapper_toolbars.map)
00212 return embed_container.winId()
00213
00214 def _on_toolbar_orientation_changed(self, toolbar_object_name):
00215 embed_container = self._embed_containers[toolbar_object_name]
00216 toolbar = self._embed_toolbars[toolbar_object_name]
00217 self._dbus_container_service.toolbar_orientation_changed(embed_container.winId(), toolbar.orientation() == Qt.Horizontal)
00218
00219 def unembed_toolbar(self, toolbar_object_name):
00220 embed_container = self._embed_containers[toolbar_object_name]
00221 del self._embed_containers[toolbar_object_name]
00222 del self._embed_toolbars[toolbar_object_name]
00223 self.remove_toolbar(embed_container)
00224 embed_container.close()