You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

442 lines
14 KiB

  1. /*
  2. * Copyright (C) 2008-2009 Nick Schermer <nick@xfce.org>
  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. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program; if not, write to the Free Software Foundation, Inc.,
  14. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include <config.h>
  18. #endif
  19. #ifdef HAVE_SYS_PRCTL_H
  20. #include <sys/prctl.h>
  21. #endif
  22. #ifdef HAVE_STDIO_H
  23. #include <stdio.h>
  24. #endif
  25. #ifdef HAVE_STDLIB_H
  26. #include <stdlib.h>
  27. #endif
  28. #ifdef HAVE_STRING_H
  29. #include <string.h>
  30. #endif
  31. #include <dbus/dbus.h>
  32. #include <dbus/dbus-glib.h>
  33. #include <dbus/dbus-glib-lowlevel.h>
  34. #include <gtk/gtk.h>
  35. #include <common/panel-private.h>
  36. #include <common/panel-dbus.h>
  37. #include <libxfce4util/libxfce4util.h>
  38. #include <libxfce4panel/libxfce4panel.h>
  39. #include <libxfce4panel/xfce-panel-plugin-provider.h>
  40. #include <wrapper/wrapper-plug.h>
  41. #include <wrapper/wrapper-module.h>
  42. #include <wrapper/wrapper-dbus-client-infos.h>
  43. static GQuark plug_quark = 0;
  44. static gboolean gproxy_destroyed = FALSE;
  45. static gint retval = PLUGIN_EXIT_FAILURE;
  46. static void
  47. wrapper_gproxy_set (DBusGProxy *dbus_gproxy,
  48. const GPtrArray *array,
  49. XfcePanelPluginProvider *provider)
  50. {
  51. WrapperPlug *plug;
  52. guint i;
  53. GValue *value;
  54. XfcePanelPluginProviderPropType type;
  55. GValue msg = { 0, };
  56. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
  57. g_value_init (&msg, PANEL_TYPE_DBUS_SET_PROPERTY);
  58. for (i = 0; i < array->len; i++)
  59. {
  60. g_value_set_static_boxed (&msg, g_ptr_array_index (array, i));
  61. if (!dbus_g_type_struct_get (&msg,
  62. DBUS_SET_TYPE, &type,
  63. DBUS_SET_VALUE, &value,
  64. G_MAXUINT))
  65. {
  66. panel_assert_not_reached ();
  67. continue;
  68. }
  69. switch (type)
  70. {
  71. case PROVIDER_PROP_TYPE_SET_SIZE:
  72. xfce_panel_plugin_provider_set_size (provider, g_value_get_int (value));
  73. break;
  74. case PROVIDER_PROP_TYPE_SET_MODE:
  75. xfce_panel_plugin_provider_set_mode (provider, g_value_get_int (value));
  76. break;
  77. case PROVIDER_PROP_TYPE_SET_SCREEN_POSITION:
  78. xfce_panel_plugin_provider_set_screen_position (provider, g_value_get_int (value));
  79. break;
  80. case PROVIDER_PROP_TYPE_SET_NROWS:
  81. xfce_panel_plugin_provider_set_nrows (provider, g_value_get_int (value));
  82. break;
  83. case PROVIDER_PROP_TYPE_SET_LOCKED:
  84. xfce_panel_plugin_provider_set_locked (provider, g_value_get_boolean (value));
  85. break;
  86. case PROVIDER_PROP_TYPE_SET_SENSITIVE:
  87. gtk_widget_set_sensitive (GTK_WIDGET (provider), g_value_get_boolean (value));
  88. break;
  89. case PROVIDER_PROP_TYPE_SET_BACKGROUND_ALPHA:
  90. case PROVIDER_PROP_TYPE_SET_BACKGROUND_COLOR:
  91. case PROVIDER_PROP_TYPE_SET_BACKGROUND_IMAGE:
  92. case PROVIDER_PROP_TYPE_ACTION_BACKGROUND_UNSET:
  93. plug = g_object_get_qdata (G_OBJECT (provider), plug_quark);
  94. if (type == PROVIDER_PROP_TYPE_SET_BACKGROUND_ALPHA)
  95. wrapper_plug_set_background_alpha (plug, g_value_get_double (value));
  96. else if (type == PROVIDER_PROP_TYPE_SET_BACKGROUND_COLOR)
  97. wrapper_plug_set_background_color (plug, g_value_get_string (value));
  98. else if (type == PROVIDER_PROP_TYPE_SET_BACKGROUND_IMAGE)
  99. wrapper_plug_set_background_image (plug, g_value_get_string (value));
  100. else /* PROVIDER_PROP_TYPE_ACTION_BACKGROUND_UNSET */
  101. wrapper_plug_set_background_color (plug, NULL);
  102. break;
  103. case PROVIDER_PROP_TYPE_ACTION_REMOVED:
  104. xfce_panel_plugin_provider_removed (provider);
  105. break;
  106. case PROVIDER_PROP_TYPE_ACTION_SAVE:
  107. xfce_panel_plugin_provider_save (provider);
  108. break;
  109. case PROVIDER_PROP_TYPE_ACTION_QUIT_FOR_RESTART:
  110. retval = PLUGIN_EXIT_SUCCESS_AND_RESTART;
  111. case PROVIDER_PROP_TYPE_ACTION_QUIT:
  112. gtk_main_quit ();
  113. break;
  114. case PROVIDER_PROP_TYPE_ACTION_SHOW_CONFIGURE:
  115. xfce_panel_plugin_provider_show_configure (provider);
  116. break;
  117. case PROVIDER_PROP_TYPE_ACTION_SHOW_ABOUT:
  118. xfce_panel_plugin_provider_show_about (provider);
  119. break;
  120. case PROVIDER_PROP_TYPE_ACTION_ASK_REMOVE:
  121. xfce_panel_plugin_provider_ask_remove (provider);
  122. break;
  123. default:
  124. panel_assert_not_reached ();
  125. break;
  126. }
  127. g_value_unset (value);
  128. g_free (value);
  129. }
  130. }
  131. static void
  132. wrapper_gproxy_remote_event (DBusGProxy *dbus_gproxy,
  133. const gchar *name,
  134. const GValue *value,
  135. guint handle,
  136. XfcePanelPluginProvider *provider)
  137. {
  138. const GValue *real_value;
  139. gboolean result;
  140. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
  141. if (G_VALUE_HOLDS_UCHAR (value)
  142. && g_value_get_uchar (value) == '\0')
  143. real_value = NULL;
  144. else
  145. real_value = value;
  146. result = xfce_panel_plugin_provider_remote_event (provider, name, real_value, NULL);
  147. wrapper_dbus_remote_event_result (dbus_gproxy, handle, result, NULL);
  148. }
  149. static void
  150. wrapper_marshal_VOID__STRING_BOXED_UINT (GClosure *closure,
  151. GValue *return_value G_GNUC_UNUSED,
  152. guint n_param_values,
  153. const GValue *param_values,
  154. gpointer invocation_hint G_GNUC_UNUSED,
  155. gpointer marshal_data)
  156. {
  157. typedef void (*GMarshalFunc_VOID__STRING_BOXED_UINT) (gpointer data1,
  158. gpointer arg_1,
  159. gpointer arg_2,
  160. guint arg_3,
  161. gpointer data2);
  162. register GMarshalFunc_VOID__STRING_BOXED_UINT callback;
  163. register GCClosure *cc = (GCClosure*) closure;
  164. register gpointer data1, data2;
  165. panel_return_if_fail (n_param_values == 4);
  166. if (G_CCLOSURE_SWAP_DATA (closure))
  167. {
  168. data1 = closure->data;
  169. data2 = g_value_peek_pointer (param_values + 0);
  170. }
  171. else
  172. {
  173. data1 = g_value_peek_pointer (param_values + 0);
  174. data2 = closure->data;
  175. }
  176. callback = (GMarshalFunc_VOID__STRING_BOXED_UINT) (marshal_data ? marshal_data : cc->callback);
  177. callback (data1,
  178. g_value_peek_pointer (param_values + 1),
  179. g_value_peek_pointer (param_values + 2),
  180. g_value_get_uint (param_values + 3),
  181. data2);
  182. }
  183. static void
  184. wrapper_gproxy_provider_signal (XfcePanelPluginProvider *provider,
  185. XfcePanelPluginProviderSignal provider_signal,
  186. DBusGProxy *dbus_gproxy)
  187. {
  188. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
  189. /* send the provider signal to the panel */
  190. wrapper_dbus_provider_signal (dbus_gproxy, provider_signal, NULL);
  191. }
  192. static void
  193. wrapper_gproxy_destroyed (DBusGProxy *dbus_gproxy)
  194. {
  195. /* we lost communication with the panel, silently close the wrapper */
  196. gproxy_destroyed = TRUE;
  197. gtk_main_quit ();
  198. }
  199. gint
  200. main (gint argc, gchar **argv)
  201. {
  202. #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_NAME)
  203. gchar process_name[16];
  204. #endif
  205. GModule *library = NULL;
  206. XfcePanelPluginPreInit preinit_func;
  207. DBusGConnection *dbus_gconnection;
  208. DBusGProxy *dbus_gproxy = NULL;
  209. WrapperModule *module = NULL;
  210. WrapperPlug *plug;
  211. GtkWidget *provider;
  212. gchar *path;
  213. guint gproxy_destroy_id = 0;
  214. GError *error = NULL;
  215. const gchar *filename;
  216. gint unique_id;
  217. GdkNativeWindow socket_id;
  218. const gchar *name;
  219. const gchar *display_name;
  220. const gchar *comment;
  221. gchar **arguments;
  222. /* set translation domain */
  223. xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
  224. #ifdef G_ENABLE_DEBUG
  225. /* terminate the program on warnings and critical messages */
  226. g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
  227. #endif
  228. /* check if we have all the reuiqred arguments */
  229. if (G_UNLIKELY (argc < PLUGIN_ARGV_ARGUMENTS))
  230. {
  231. g_critical ("Not enough arguments are passed to the wrapper");
  232. return PLUGIN_EXIT_ARGUMENTS_FAILED;
  233. }
  234. /* put all arguments in understandable strings */
  235. filename = argv[PLUGIN_ARGV_FILENAME];
  236. unique_id = strtol (argv[PLUGIN_ARGV_UNIQUE_ID], NULL, 0);
  237. socket_id = strtol (argv[PLUGIN_ARGV_SOCKET_ID], NULL, 0);
  238. name = argv[PLUGIN_ARGV_NAME];
  239. display_name = argv[PLUGIN_ARGV_DISPLAY_NAME];
  240. comment = argv[PLUGIN_ARGV_COMMENT];
  241. arguments = argv + PLUGIN_ARGV_ARGUMENTS;
  242. #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_NAME)
  243. /* change the process name to something that makes sence */
  244. g_snprintf (process_name, sizeof (process_name), "panel-%d-%s",
  245. unique_id, name);
  246. if (prctl (PR_SET_NAME, (gulong) process_name, 0, 0, 0) == -1)
  247. g_warning ("Failed to change the process name to \"%s\".", process_name);
  248. #endif
  249. /* open the plugin module */
  250. library = g_module_open (filename, G_MODULE_BIND_LOCAL);
  251. if (G_UNLIKELY (library == NULL))
  252. {
  253. g_set_error (&error, 0, 0, "Failed to open plugin module \"%s\": %s",
  254. filename, g_module_error ());
  255. goto leave;
  256. }
  257. /* check for a plugin preinit function */
  258. if (g_module_symbol (library, "xfce_panel_module_preinit", (gpointer) &preinit_func)
  259. && preinit_func != NULL
  260. && (*preinit_func) (argc, argv) == FALSE)
  261. {
  262. retval = PLUGIN_EXIT_PREINIT_FAILED;
  263. goto leave;
  264. }
  265. gtk_init (&argc, &argv);
  266. /* connect the dbus proxy */
  267. dbus_gconnection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
  268. if (G_UNLIKELY (dbus_gconnection == NULL))
  269. goto leave;
  270. path = g_strdup_printf (PANEL_DBUS_WRAPPER_PATH, unique_id);
  271. dbus_gproxy = dbus_g_proxy_new_for_name_owner (dbus_gconnection,
  272. PANEL_DBUS_NAME,
  273. path,
  274. PANEL_DBUS_WRAPPER_INTERFACE,
  275. &error);
  276. g_free (path);
  277. if (G_UNLIKELY (dbus_gproxy == NULL))
  278. goto leave;
  279. /* quit when the proxy is destroyed (panel segfault for example) */
  280. gproxy_destroy_id = g_signal_connect (G_OBJECT (dbus_gproxy), "destroy",
  281. G_CALLBACK (wrapper_gproxy_destroyed), NULL);
  282. /* create the type module */
  283. module = wrapper_module_new (library);
  284. /* create the plugin provider */
  285. provider = wrapper_module_new_provider (module,
  286. gdk_screen_get_default (),
  287. name, unique_id,
  288. display_name, comment,
  289. arguments);
  290. if (G_LIKELY (provider != NULL))
  291. {
  292. /* create the wrapper plug */
  293. plug = wrapper_plug_new (socket_id);
  294. gtk_container_add (GTK_CONTAINER (plug), GTK_WIDGET (provider));
  295. g_object_add_weak_pointer (G_OBJECT (plug), (gpointer *) &plug);
  296. gtk_widget_show (GTK_WIDGET (plug));
  297. /* set plug data to provider */
  298. plug_quark = g_quark_from_static_string ("plug-quark");
  299. g_object_set_qdata (G_OBJECT (provider), plug_quark, plug);
  300. /* monitor provider signals */
  301. g_signal_connect (G_OBJECT (provider), "provider-signal",
  302. G_CALLBACK (wrapper_gproxy_provider_signal), dbus_gproxy);
  303. /* connect to service signals */
  304. dbus_g_proxy_add_signal (dbus_gproxy, "Set",
  305. PANEL_TYPE_DBUS_SET_SIGNAL, G_TYPE_INVALID);
  306. dbus_g_proxy_connect_signal (dbus_gproxy, "Set",
  307. G_CALLBACK (wrapper_gproxy_set), g_object_ref (provider),
  308. (GClosureNotify) g_object_unref);
  309. dbus_g_object_register_marshaller (wrapper_marshal_VOID__STRING_BOXED_UINT,
  310. G_TYPE_NONE, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_UINT, G_TYPE_INVALID);
  311. dbus_g_proxy_add_signal (dbus_gproxy, "RemoteEvent",
  312. G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_UINT, G_TYPE_INVALID);
  313. dbus_g_proxy_connect_signal (dbus_gproxy, "RemoteEvent",
  314. G_CALLBACK (wrapper_gproxy_remote_event), g_object_ref (provider),
  315. (GClosureNotify) g_object_unref);
  316. /* show the plugin */
  317. gtk_widget_show (GTK_WIDGET (provider));
  318. gtk_main ();
  319. /* disconnect signals */
  320. if (!gproxy_destroyed)
  321. {
  322. dbus_g_proxy_disconnect_signal (dbus_gproxy, "Set",
  323. G_CALLBACK (wrapper_gproxy_set), provider);
  324. dbus_g_proxy_disconnect_signal (dbus_gproxy, "RemoteEvent",
  325. G_CALLBACK (wrapper_gproxy_remote_event), provider);
  326. }
  327. /* destroy the plug and provider */
  328. if (plug != NULL)
  329. gtk_widget_destroy (GTK_WIDGET (plug));
  330. if (retval != PLUGIN_EXIT_SUCCESS_AND_RESTART)
  331. retval = PLUGIN_EXIT_SUCCESS;
  332. }
  333. else
  334. {
  335. retval = PLUGIN_EXIT_NO_PROVIDER;
  336. }
  337. leave:
  338. if (G_LIKELY (dbus_gproxy != NULL))
  339. {
  340. if (G_LIKELY (gproxy_destroy_id != 0 && !gproxy_destroyed))
  341. g_signal_handler_disconnect (G_OBJECT (dbus_gproxy), gproxy_destroy_id);
  342. g_object_unref (G_OBJECT (dbus_gproxy));
  343. }
  344. if (G_LIKELY (module != NULL))
  345. g_object_unref (G_OBJECT (module));
  346. if (G_LIKELY (library != NULL))
  347. g_module_close (library);
  348. if (G_UNLIKELY (error != NULL))
  349. {
  350. g_critical ("Wrapper %s-%d: %s.", name,
  351. unique_id, error->message);
  352. g_error_free (error);
  353. }
  354. return retval;
  355. }