Codebase list cairo-dock-plug-ins / 25f6890
Imported Upstream version 3.1.2 Youhei SASAKI 10 years ago
15 changed file(s) with 417 addition(s) and 96 deletion(s). Raw diff Collapse all Expand all
1010 ########### project ###############
1111
1212 project ("cairo-dock-plugins")
13 set (VERSION "3.1.1")
13 set (VERSION "3.1.2")
1414
1515 add_definitions (-std=c99 -Wall) # -Wextra -Wwrite-strings -Wuninitialized -Werror-implicit-function-declaration -Wstrict-prototypes -Wreturn-type -Wparentheses -Warray-bounds) # removed for stable versions: -Wstrict-prototypes #-Wunreachable-code -Wno-unused-parameter -Wall
1616 if (NOT ${CMAKE_BUILD_TYPE})
145145 ############# INDICATOR-APPLET #################
146146 message (STATUS "> Indicator-Applet:")
147147 # Note: the names of dbusmenu-glib, dbusmenu-gtk and indicator have changed...
148 ## DBusMenu Glib
148149 set (DBUSMENU_MODULE dbusmenu-glib-0.4)
149150 pkg_check_modules (DBUSMENU ${DBUSMENU_MODULE})
150151 if (NOT "${DBUSMENU_FOUND}")
155156 set (INDICATOR_APPLICATIONADDED_HAS_HINT 1) # now the ApplicationAdded signal (Status-Notifier) has a new parameter (hint) => https://code.launchpad.net/~ted/indicator-application/name-hints/+merge/67213
156157 endif()
157158
159 ## DBusMenu Gtk
158160 if ("${gtkversion}" STREQUAL "2")
159161 set (DBUSMENU_GTK_MODULE dbusmenu-gtk-0.4)
160162 else()
170172 pkg_check_modules (DBUSMENU_GTK ${DBUSMENU_GTK_MODULE})
171173 endif()
172174
175 ## Indicator
173176 if ("${gtkversion}" STREQUAL "2")
174177 set (INDICATOR_APPLET_MODULE indicator-0.4)
175178 else()
187190 pkg_check_modules (INDICATOR_APPLET ${INDICATOR_APPLET_MODULE})
188191 endif()
189192
193 ## libido
190194 if ("${gtkversion}" STREQUAL "2")
191195 set (IDO_MODULE libido-0.1)
192196 else()
194198 endif()
195199 pkg_check_modules (IDO ${IDO_MODULE})
196200
201 ## Extract versions of DBusMenu
197202 if ("${DBUSMENU_FOUND}" STREQUAL "1" AND "${DBUSMENU_GTK_FOUND}" STREQUAL "1")
198203 STRING (REGEX REPLACE "\\..*" "" DBUSMENU_MAJOR "${DBUSMENU_VERSION}")
199204 STRING (REGEX REPLACE "[0-9]*\\.([^ ]+)" "\\1" DBUSMENU_MINOR "${DBUSMENU_VERSION}") # 0.1.7 => 1.7
216221 endif()
217222 endif()
218223
224 ## Extract version of indicator
219225 if ("${INDICATOR_APPLET_FOUND}" STREQUAL "1")
220226 STRING (REGEX REPLACE "\\..*" "" INDICATOR_MAJOR "${INDICATOR_APPLET_VERSION}")
221227 STRING (REGEX REPLACE "[0-9]*\\.([^ ]+)" "\\1" INDICATOR_MINOR "${INDICATOR_APPLET_VERSION}") # 0.1.7 => 1.7
263269 if ("${with_indicator3}" STREQUAL "yes")
264270 add_subdirectory (Indicator-applet3)
265271 endif()
266 add_subdirectory (Indicator-applet)
267 set (with_indicator "yes")
272 ## DBusMenu is needed for Indicator-applet
273 if ("${DBUSMENU_FOUND}" STREQUAL "1" AND "${DBUSMENU_GTK_FOUND}" STREQUAL "1")
274 add_subdirectory (Indicator-applet)
275 set (with_indicator "yes")
276 endif()
268277 endif()
269278
270279 if (NOT "${DBUSMENU_FOUND}" STREQUAL "1" OR NOT "${DBUSMENU_GTK_FOUND}" STREQUAL "1" OR NOT "${INDICATOR_APPLET_FOUND}" STREQUAL "1")
343352 ############# ALSA_MIXER #################
344353 message (STATUS "> AlsaMixer:")
345354 set (with_alsa "no")
355 set (with_soundmenu "no")
346356 if (NOT "${enable-alsa-mixer}" STREQUAL "no")
347357 pkg_check_modules (ALSA_MIXER_PACKAGE alsa)
348358 if ("${ALSA_MIXER_PACKAGE_FOUND}" STREQUAL "")
7676 }
7777 CD_APPLET_LEAVE();
7878 }
79
80 static gboolean _cd_check_edit_menu_cmd (const gchar *cWhich)
81 {
82 gchar *cResult = cairo_dock_launch_command_sync (cWhich); // Gnome (2 + 3(?)) + XFCE(?)
83 gboolean bResult = (cResult != NULL && *cResult == '/');
84 g_free (cResult);
85 return bResult;
86 }
87
7988 CD_APPLET_ON_BUILD_MENU_BEGIN
8089 gchar *cLabel = g_strdup_printf ("%s (%s)", D_("Quick launch"), D_("middle-click"));
8190 CD_APPLET_ADD_IN_MENU_WITH_STOCK (cLabel, GTK_STOCK_EXECUTE, cd_menu_show_hide_quick_launch, CD_APPLET_MY_MENU);
8695 if (!myConfig.cConfigureMenuCommand && !bEditMenuCmdChecked)
8796 {
8897 bEditMenuCmdChecked = TRUE;
89 gchar *cResult = cairo_dock_launch_command_sync ("which alacarte"); // Gnome (2 + 3(?)) + XFCE(?)
90 if (cResult != NULL && *cResult == '/')
91 {
98 if (_cd_check_edit_menu_cmd ("which alacarte"))
9299 s_cEditMenuCmd = "alacarte";
93 }
94 else
95 {
96 g_free (cResult);
97 cResult = cairo_dock_launch_command_sync ("which kmenuedit"); // KDE
98 if (cResult != NULL && *cResult == '/')
99 s_cEditMenuCmd = "kmenuedit";
100 } /// TODO: handle other DE ...
101 g_free (cResult);
100 else if (_cd_check_edit_menu_cmd ("which kmenuedit"))
101 s_cEditMenuCmd = "kmenuedit";
102 else if (_cd_check_edit_menu_cmd ("which menulibre"))
103 s_cEditMenuCmd = "menulibre";
102104 }
103105 if (myConfig.cConfigureMenuCommand || s_cEditMenuCmd)
104106 CD_APPLET_ADD_IN_MENU_WITH_STOCK (D_("Configure menu"), GTK_STOCK_PREFERENCES, _cd_menu_configure_menu, CD_APPLET_MY_MENU);
720720 cLine = g_strdup (pItem->cDescription);
721721 cd_rssreader_cut_line (cLine, pLayout, w);
722722 pLinkButton = gtk_label_new (cLine);
723 gtk_label_set_selectable (GTK_LABEL (pLinkButton), TRUE);
723724 g_free (cLine);
724725
725726 pAlign = gtk_alignment_new (0., 0.5, 0., 0.);
774775 cairo_dock_show_temporary_dialog_with_icon (D_("No URL is defined\nYou can define one by copying the URL in the clipboard,\n and selecting \"Paste the URL\" in the menu."),
775776 myIcon,
776777 myContainer,
777 myConfig.iNotificationDuration,
778 1000*myConfig.iNotificationDuration,
778779 myDock ? "same icon" : MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
779780 else
780781 cairo_dock_show_temporary_dialog_with_icon (D_("No data\nDid you set a valid RSS feed?\nIs your connection alive?"),
781782 myIcon,
782783 myContainer,
783 myConfig.iNotificationDuration,
784 1000*myConfig.iNotificationDuration,
784785 myDock ? "same icon" : MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
785786 }
786787 }
187187 }
188188 #endif
189189
190 static void _cd_cclosure_marshal_VOID__INT_STRING_STRING (GClosure *closure,
191 GValue *return_value G_GNUC_UNUSED,
192 guint n_param_values,
193 const GValue *param_values,
194 gpointer invocation_hint G_GNUC_UNUSED,
195 gpointer marshal_data)
196 {
197 //cd_debug ("=== %s ()", __func__);
198 typedef void (*GMarshalFunc_VOID__INT_STRING_STRING) (
199 gpointer data1,
200 gint arg_1,
201 gchar *arg_2,
202 gchar *arg_3,
203 gpointer data2);
204 register GMarshalFunc_VOID__INT_STRING_STRING callback;
205 register GCClosure *cc = (GCClosure*) closure;
206 register gpointer data1, data2;
207 g_return_if_fail (n_param_values == 4); // return_value est NULL ici, car la callback ne renvoit rien.
208
209 if (G_CCLOSURE_SWAP_DATA (closure))
210 {
211 data1 = closure->data;
212 data2 = g_value_peek_pointer (param_values + 0);
213 }
214 else
215 {
216 data1 = g_value_peek_pointer (param_values + 0);
217 data2 = closure->data;
218 }
219 callback = (GMarshalFunc_VOID__INT_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
220
221 callback (data1,
222 g_value_get_int (param_values + 1),
223 (char*) g_value_get_string (param_values + 2),
224 (char*) g_value_get_string (param_values + 3),
225 data2);
226 }
227
228 static void _cd_cclosure_marshal_VOID__INT_STRING (GClosure *closure,
229 GValue *return_value G_GNUC_UNUSED,
230 guint n_param_values,
231 const GValue *param_values,
232 gpointer invocation_hint G_GNUC_UNUSED,
233 gpointer marshal_data)
234 {
235 //cd_debug ("=== %s ()", __func__);
236 typedef void (*GMarshalFunc_VOID__INT_STRING) (
237 gpointer data1,
238 gint arg_1,
239 gchar *arg_2,
240 gpointer data2);
241 register GMarshalFunc_VOID__INT_STRING callback;
242 register GCClosure *cc = (GCClosure*) closure;
243 register gpointer data1, data2;
244 g_return_if_fail (n_param_values == 3); // return_value est NULL ici, car la callback ne renvoit rien.
245
246 if (G_CCLOSURE_SWAP_DATA (closure))
247 {
248 data1 = closure->data;
249 data2 = g_value_peek_pointer (param_values + 0);
250 }
251 else
252 {
253 data1 = g_value_peek_pointer (param_values + 0);
254 data2 = closure->data;
255 }
256 callback = (GMarshalFunc_VOID__INT_STRING) (marshal_data ? marshal_data : cc->callback);
257
258 callback (data1,
259 g_value_get_int (param_values + 1),
260 (char*) g_value_get_string (param_values + 2),
261 data2);
262 }
263
190264 ///////////////
191265 /// Signals ///
192266 ///////////////
270344 CD_APPLET_LEAVE ();
271345 }
272346
347 static void on_application_icon_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cIconName, const gchar *cIconDesc, CairoDockModuleInstance *myApplet)
348 {
349 CD_APPLET_ENTER;
350 cd_debug ("=== %s (%d, %s, %s)", __func__, iPosition, cIconName, cIconDesc);
351
352 CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
353 g_return_if_fail (pItem != NULL);
354
355 if (g_strcmp0 (pItem->cIconName, cIconName) == 0) // discard useless updates (skype...)
356 return;
357 g_free (pItem->cIconName);
358 pItem->cIconName = g_strdup (cIconName);
359 g_free (pItem->cAccessibleDesc);
360 pItem->cAccessibleDesc = g_strdup (cIconDesc);
361
362 if (pItem->iStatus != CD_STATUS_NEEDS_ATTENTION)
363 {
364 cd_satus_notifier_update_item_image (pItem);
365 }
366
367 CD_APPLET_LEAVE ();
368 }
369
370 static void on_application_icon_theme_path_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cIconThemePath, CairoDockModuleInstance *myApplet)
371 {
372 CD_APPLET_ENTER;
373 cd_debug ("=== %s (%d, %s)", __func__, iPosition, cIconThemePath);
374
375 CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
376 g_return_if_fail (pItem != NULL);
377
378 if (g_strcmp0 (cIconThemePath, pItem->cIconThemePath) != 0)
379 {
380 if (pItem->cIconThemePath != NULL) // if the item previously provided a theme, remove it first.
381 cd_satus_notifier_remove_theme_path (pItem->cIconThemePath);
382 g_free (pItem->cIconThemePath);
383 pItem->cIconThemePath = g_strdup (cIconThemePath);
384
385 cd_satus_notifier_add_theme_path (cIconThemePath); // and add the new one.
386
387 if (pItem->cIconName != NULL)
388 {
389 cd_satus_notifier_update_item_image (pItem);
390 }
391 }
392 CD_APPLET_LEAVE ();
393 }
394
395 static void on_application_label_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cLabel, const gchar *cLabelGuide, CairoDockModuleInstance *myApplet)
396 {
397 CD_APPLET_ENTER;
398 cd_debug ("=== %s (%d, %s, %s)", __func__, iPosition, cLabel, cLabelGuide);
399
400 CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
401 g_return_if_fail (pItem != NULL);
402
403 g_free (pItem->cLabel);
404 pItem->cLabel = g_strdup (cLabel);
405 g_free (pItem->cLabelGuide);
406 pItem->cLabelGuide = g_strdup (cLabelGuide);
407
408 CD_APPLET_LEAVE ();
409 }
410
411 static void on_application_title_changed (DBusGProxy *proxy_watcher, gint iPosition, const gchar *cTitle, CairoDockModuleInstance *myApplet)
412 {
413 CD_APPLET_ENTER;
414 cd_debug ("=== %s (%d, %s)", __func__, iPosition, cTitle);
415
416 CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_position (iPosition);
417 g_return_if_fail (pItem != NULL);
418
419 if (cTitle != NULL)
420 {
421 g_free (pItem->cTitle);
422 pItem->cTitle = g_strdup (cTitle);
423 }
424
425 CD_APPLET_LEAVE ();
426 }
273427
274428 /////////////////
275429 /// Get Items ///
522676 G_TYPE_INVALID);
523677 dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationRemoved",
524678 G_CALLBACK(on_removed_application), myApplet, NULL);
525 // TODO? ApplicationIconChanged, ApplicationIconThemePathChanged, ApplicationLabelChanged, ApplicationTitleChanged
679
680 // we add the following signals because some program don't support the StatusNotifier API (skype, once again...) but only the IAS one.
681 dbus_g_object_register_marshaller(_cd_cclosure_marshal_VOID__INT_STRING_STRING,
682 G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
683 dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconChanged",
684 G_TYPE_INT, // position
685 G_TYPE_STRING, // icon name
686 G_TYPE_STRING, // icon desc (?)
687 G_TYPE_INVALID);
688 dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconChanged",
689 G_CALLBACK(on_application_icon_changed), myApplet, NULL);
690
691 dbus_g_object_register_marshaller(_cd_cclosure_marshal_VOID__INT_STRING,
692 G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID);
693 dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconThemePathChanged",
694 G_TYPE_INT, // position
695 G_TYPE_STRING, // icon name
696 G_TYPE_STRING, // icon desc (Note: I'm quite sure they will eventually remove it ...)
697 G_TYPE_INVALID);
698 dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationIconThemePathChanged",
699 G_CALLBACK(on_application_icon_theme_path_changed), myApplet, NULL);
700
701 dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationLabelChanged",
702 G_TYPE_INT, // position
703 G_TYPE_STRING, // label
704 G_TYPE_STRING, // guide
705 G_TYPE_INVALID);
706 dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationLabelChanged",
707 G_CALLBACK(on_application_label_changed), myApplet, NULL);
708
709 dbus_g_proxy_add_signal(myData.pProxyIndicatorApplicationService, "ApplicationTitleChanged",
710 G_TYPE_INT, // position
711 G_TYPE_STRING, // title
712 G_TYPE_INVALID);
713 dbus_g_proxy_connect_signal(myData.pProxyIndicatorApplicationService, "ApplicationTitleChanged",
714 G_CALLBACK(on_application_title_changed), myApplet, NULL);
526715 }
527716
528717 //////////////////
116116 CDStatusNotifierItem *pItem;
117117 for (i = 0; pApplications[i] != NULL; i ++)
118118 {
119 g_print (" + '%s'\n", pApplications[i]); // service + path
119 cd_message (" + '%s'", pApplications[i]); // service + path
120120 if (*pApplications[i] == '\0')
121121 continue;
122122
135135 g_free (cService);
136136 if (! pItem)
137137 continue;
138 cd_debug ("=== => + %s", pItem->cTitle);
138 cd_debug ("=== => + %s", pItem->cTitle?pItem->cTitle:pItem->cLabel);
139139 myData.pItems = g_list_prepend (myData.pItems, pItem);
140140 }
141141
3232 #define CD_STATUS_NOTIFIER_HOST_ADDR "org.kde.StatusNotifierHost"
3333
3434
35 static CDStatusNotifierItem * _cd_satus_notifier_find_item_from_service (const gchar *cService)
35 CDStatusNotifierItem * cd_satus_notifier_find_item_from_service (const gchar *cService)
3636 {
3737 g_return_val_if_fail (cService != NULL, NULL);
3838 CDStatusNotifierItem *pItem;
4646 return NULL;
4747 }
4848
49 static CDStatusNotifierItem * _cd_satus_notifier_find_item_from_position (int iPosition)
49 CDStatusNotifierItem * cd_satus_notifier_find_item_from_position (int iPosition)
5050 {
5151 CDStatusNotifierItem *pItem;
5252 GList *it;
6666
6767 void cd_satus_notifier_add_new_item_with_default (const gchar *cService, const gchar *cObjectPath, int iPosition, const gchar *cIconName, const gchar *cIconThemePath, const gchar *cLabel)
6868 {
69 CDStatusNotifierItem *pItem = _cd_satus_notifier_find_item_from_service (cService);
69 CDStatusNotifierItem *pItem = cd_satus_notifier_find_item_from_service (cService);
7070 g_return_if_fail (pItem == NULL); // on evite d'ajouter 2 fois le meme service.
7171
7272 pItem = cd_satus_notifier_create_item (cService, cObjectPath);
8888 if (pItem->cLabel == NULL)
8989 pItem->cLabel = g_strdup (cLabel);
9090
91 if (pItem->cMenuPath == NULL)
91 if (pItem->cMenuPath == NULL) /// this is questionnable ... if the item doesn't provide a menu, this could be that it really doesn't use a dbusmenu (but rather relies on the ContextMenu).
92 {
93 cd_debug ("No menu defined for '%s', using '%s' as the menu path", cService, cObjectPath);
9294 pItem->cMenuPath = g_strdup (cObjectPath);
95 }
96 // build the dbusmenu right now, so that the menu is complete when the user first click on the item (otherwise, the menu is not placed correctly).
97 cd_satus_notifier_build_item_dbusmenu (pItem);
9398
9499 pItem->iPosition = iPosition;
95100 if (pItem->cLabel == NULL && pItem->cTitle == NULL)
112117
113118 void cd_satus_notifier_remove_item (const gchar *cService, int iPosition)
114119 {
115 CDStatusNotifierItem *pItem = (cService ? _cd_satus_notifier_find_item_from_service (cService) : _cd_satus_notifier_find_item_from_position (iPosition));
120 CDStatusNotifierItem *pItem = (cService ? cd_satus_notifier_find_item_from_service (cService) : cd_satus_notifier_find_item_from_position (iPosition));
116121 g_return_if_fail (pItem != NULL);
117122
118123 myData.pItems = g_list_remove (myData.pItems, pItem);
218223 g_hash_table_remove (myData.pThemePaths, cThemePath); // on le supprime de la table.
219224
220225 cairo_dock_remove_path_from_icon_theme (cThemePath);
221 /**GtkIconTheme *pIconTheme = gtk_icon_theme_get_default(); // et du theme.
222 gchar **paths = NULL;
223 gint iNbPaths = 0;
224 gtk_icon_theme_get_search_path (pIconTheme, &paths, &iNbPaths);
225
226 int i;
227 for (i = 0; i < iNbPaths; i++) // on cherche sa position dans le tableau.
228 {
229 if (strcmp (paths[i], cThemePath))
230 break;
231 }
232 if (i < iNbPaths) // trouve
233 {
234 g_free (paths[i]);
235 for (i = i+1; i < iNbPaths; i++) // on decale tous les suivants vers l'arriere.
236 {
237 paths[i-1] = paths[i];
238 }
239 paths[i-1] = NULL;
240 gtk_icon_theme_set_search_path (pIconTheme, (const gchar **)paths, iNbPaths - 1);
241 }
242
243 g_strfreev (paths);*/
244226 }
245227 else // on decremente la reference.
246228 {
2222 #include <cairo-dock.h>
2323
2424
25 CDStatusNotifierItem * cd_satus_notifier_find_item_from_service (const gchar *cService);
26
27 CDStatusNotifierItem * cd_satus_notifier_find_item_from_position (int iPosition);
28
29
2530 void cd_satus_notifier_add_new_item_with_default (const gchar *cService, const gchar *cObjectPath, int iPosition, const gchar *cIconName, const gchar *cIconThemePath, const gchar *cLabel);
2631
2732 #define cd_satus_notifier_add_new_item(cService, cObjectPath, iPosition) cd_satus_notifier_add_new_item_with_default (cService, cObjectPath, iPosition, NULL, NULL, NULL)
2424 #include "applet-struct.h"
2525 #include "applet-host.h"
2626 #include "applet-draw.h"
27 #include "applet-notifications.h"
2728 #include "applet-item.h"
2829
2930 #define CD_STATUS_NOTIFIER_ITEM_IFACE "org.kde.StatusNotifierItem"
140141 static void on_new_item_icon (DBusGProxy *proxy_item, CDStatusNotifierItem *pItem)
141142 {
142143 CD_APPLET_ENTER;
143 //g_print ("=== %s ()\n", __func__);
144 cd_debug ("=== %s ()", __func__);
144145
145146 g_free (pItem->cIconName);
146147 pItem->cIconName = cairo_dock_dbus_get_property_as_string (pItem->pProxyProps, CD_STATUS_NOTIFIER_ITEM_IFACE, "IconName");
147148 g_free (pItem->cAccessibleDesc);
148149 pItem->cAccessibleDesc = cairo_dock_dbus_get_property_as_string (pItem->pProxyProps, CD_STATUS_NOTIFIER_ITEM_IFACE, "IconAccessibleDesc");
149 //g_print ("=== new icon : %s\n", pItem->cIconName);
150 cd_debug ("=== new icon : %s", pItem->cIconName);
150151
151152 if (pItem->iStatus != CD_STATUS_NEEDS_ATTENTION)
152153 {
158159 static void on_new_item_attention_icon (DBusGProxy *proxy_item, CDStatusNotifierItem *pItem)
159160 {
160161 CD_APPLET_ENTER;
161 //g_print ("=== %s ()\n", __func__);
162 cd_debug ("=== %s ()", __func__);
162163
163164 g_free (pItem->cAttentionIconName);
164165 pItem->cAttentionIconName = cairo_dock_dbus_get_property_as_string (pItem->pProxyProps, CD_STATUS_NOTIFIER_ITEM_IFACE, "AttentionIconName");
165 //g_print ("=== new attention icon : %s\n", pItem->cAttentionIconName);
166 cd_debug ("=== new attention icon : %s", pItem->cAttentionIconName);
166167
167168 if (pItem->iStatus == CD_STATUS_NEEDS_ATTENTION)
168169 {
223224 g_free (pItem->cLabelGuide);
224225 pItem->cLabelGuide = g_strdup (cLabelGuide);
225226
226
227227 CD_APPLET_LEAVE ();
228228 }
229229
232232 CD_APPLET_ENTER;
233233 //g_print ("=== %s (%s)\n", __func__, cNewThemePath);
234234
235 g_free (pItem->cIconThemePath);
236 pItem->cIconThemePath = g_strdup (cNewThemePath);
237
238 cd_satus_notifier_update_item_image (pItem);
235 if (g_strcmp0 (cNewThemePath, pItem->cIconThemePath) != 0)
236 {
237 if (pItem->cIconThemePath != NULL) // if the item previously provided a theme, remove it first.
238 cd_satus_notifier_remove_theme_path (pItem->cIconThemePath);
239 g_free (pItem->cIconThemePath);
240 pItem->cIconThemePath = g_strdup (cNewThemePath);
241
242 cd_satus_notifier_update_item_image (pItem);
243 }
239244
240245 CD_APPLET_LEAVE ();
241246 }
329334 CD_APPLET_LEAVE ();
330335 }
331336
337 static gboolean _update_icon_delayed (CDStatusNotifierItem *pItem)
338 {
339 cd_debug ("");
340 if (pItem->cIconName != NULL)
341 {
342 cd_satus_notifier_update_item_image (pItem);
343 }
344 pItem->iSidUpdateIcon = 0;
345 return FALSE;
346 }
332347 gchar *cd_satus_notifier_search_item_icon_s_path (CDStatusNotifierItem *pItem, gint iSize)
333348 {
334349 g_return_val_if_fail (pItem != NULL, NULL);
351366 if (cIconPath == NULL) // in case we have a buggy app, try some heuristic
352367 {
353368 cIconPath = cairo_dock_search_icon_s_path (pItem->cId, iSize);
354 if (cIconPath == NULL)
369 if (cIconPath == NULL && pItem->pSurface == NULL) // only use the fallback icon if the item is still empty (to not have an invisible item).
370 {
355371 cIconPath = g_strdup (MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
372 }
373
374 // skype strikes again ! on startup, it indicates its icon theme path (a temporary folder in /tmp); BUT it copies the icons after, so for a few seconds, the icons it tells us don't exist.
375 // so we trigger an update in a few seconds.
376 if (pItem->iSidUpdateIcon == 0)
377 pItem->iSidUpdateIcon = g_timeout_add_seconds (7, (GSourceFunc)_update_icon_delayed, pItem);
356378 }
379 }
380 else if (pItem->iSidUpdateIcon != 0) // we found an icon, discard any pending update.
381 {
382 g_source_remove (pItem->iSidUpdateIcon);
383 pItem->iSidUpdateIcon = 0;
357384 }
358385
359386 return cIconPath;
402429 {
403430 g_return_val_if_fail (cService != NULL, NULL);
404431 cd_debug ("=== %s (%s, %s)", __func__, cService, cObjectPath);
432
433 // avoid creating an item that already exists. This can happen in the following case (skype):
434 // watcher starts -> dock registers to it -> dock asks the items - - - - - - - - - - - - - - - - - -> dock receives the items -> skype item is already here !
435 // -> skype creates its item -> 'new-item' is emitted -> dock receives the signal -> creates the item
436 if (cd_satus_notifier_find_item_from_service (cService) != NULL)
437 {
438 cd_debug ("The service %s / %s is already listed, skip it", cService, cObjectPath);
439 return NULL;
440 }
405441
406442 gchar *str = strchr (cService, '/'); // just to be sure.
407443 if (str)
618654 cd_satus_notifier_add_theme_path (pItem->cIconThemePath);
619655 }
620656
621 if (pItem->cMenuPath != NULL)
622 pItem->pMenu = dbusmenu_gtkmenu_new ((gchar *)pItem->cService, (gchar *)pItem->cMenuPath);
657 // build the dbusmenu right now, so that the menu is complete when the user first click on the item (otherwise, the menu is not placed correctly).
658 cd_satus_notifier_build_item_dbusmenu (pItem);
623659
624660 //\_________________ track any changes in the item.
625661 // signals supported by both.
674710 return pItem;
675711 }
676712
713 static gboolean _on_draw_menu_reposition (GtkWidget *pWidget, G_GNUC_UNUSED gpointer useless, CDStatusNotifierItem *pItem);
714
677715 void cd_free_item (CDStatusNotifierItem *pItem)
678716 {
679717 if (pItem == NULL)
681719 pItem->bInvalid = TRUE;
682720 if (pItem->iSidPopupTooltip != 0)
683721 g_source_remove (pItem->iSidPopupTooltip);
722 if (pItem->iSidUpdateIcon != 0)
723 g_source_remove (pItem->iSidUpdateIcon);
684724 if (pItem->cIconThemePath)
685725 cd_satus_notifier_remove_theme_path (pItem->cIconThemePath);
726 if (pItem->pMenu != NULL)
727 g_object_unref (pItem->pMenu); // will remove the 'reposition' callback too.
686728 g_object_unref (pItem->pProxy);
687729 g_object_unref (pItem->pProxyProps);
688730 g_free (pItem->cService);
756798 }
757799 return NULL;
758800 }
801
802
803 static gboolean _on_draw_menu_reposition (GtkWidget *pWidget, G_GNUC_UNUSED gpointer useless, CDStatusNotifierItem *pItem)
804 {
805 g_return_val_if_fail (pItem != NULL, FALSE);
806
807 int iMenuWidth = gtk_widget_get_allocated_width (pWidget);
808
809 if (pItem->iMenuWidth != iMenuWidth) // if the width has changed, reposition the menu to be sure it won't out of the screen.
810 {
811 pItem->iMenuWidth = iMenuWidth;
812 gtk_menu_reposition (GTK_MENU (pWidget));
813 }
814
815 return FALSE; // FALSE to propagate the event further.
816 }
817 void cd_satus_notifier_build_item_dbusmenu (CDStatusNotifierItem *pItem)
818 {
819 if (pItem->pMenu == NULL) // menu not yet built
820 {
821 if (pItem->cMenuPath != NULL && *pItem->cMenuPath != '\0' && strcmp (pItem->cMenuPath, "/NO_DBUSMENU") != 0) // hopefully, if the item doesn't provide a dbusmenu, it will not set something different as these 2 choices (ex.: Klipper).
822 {
823 pItem->pMenu = dbusmenu_gtkmenu_new ((gchar *)pItem->cService, (gchar *)pItem->cMenuPath);
824 if (g_object_is_floating (pItem->pMenu)) // claim ownership on the menu.
825 g_object_ref_sink (pItem->pMenu);
826 /* Position of the menu: GTK doesn't do its job :-/
827 * e.g. with Dropbox: the menu is out of the screen every time
828 * something has changed in this menu (it displays 'connecting',
829 * free space available, etc.) -> we need to reposition it.
830 * (maybe it's due to a delay because Python and DBus are slower...)
831 * We can't watch the 'configure' event (which should be triggered
832 * each time the menu is resized) because it seems this notification
833 * is not send...
834 * This is why we need to watch the 'draw' event...
835 */
836 g_signal_connect (G_OBJECT (pItem->pMenu),
837 #if (GTK_MAJOR_VERSION < 3)
838 "expose-event",
839 #else
840 "draw",
841 #endif
842 G_CALLBACK (_on_draw_menu_reposition),
843 pItem);
844 }
845 }
846 }
3939 #define _item_is_visible(item) ((item)->iStatus != CD_STATUS_PASSIVE || ! myConfig.bHideInactive)
4040
4141
42 void cd_satus_notifier_build_item_dbusmenu (CDStatusNotifierItem *pItem);
43
44
4245 #endif
8383 }
8484
8585
86 static inline gboolean _popup_menu (CDStatusNotifierItem *pItem, Icon *pIcon, CairoContainer *pContainer)
86 static gboolean _popup_menu (CDStatusNotifierItem *pItem, Icon *pIcon, CairoContainer *pContainer)
8787 {
8888 gboolean r = FALSE;
89 if (pItem->cMenuPath != NULL && *pItem->cMenuPath != '\0' && strcmp (pItem->cMenuPath, "/NO_DBUSMENU") != 0) // hopefully, if the item doesn't have a dbusmenu, it will not set something different as these 2 choices.
90 {
91 if (pItem->pMenu == NULL)
92 pItem->pMenu = dbusmenu_gtkmenu_new ((gchar *)pItem->cService, (gchar *)pItem->cMenuPath);
93 if (pItem->pMenu != NULL)
94 {
95 cairo_dock_popup_menu_on_icon (GTK_WIDGET (pItem->pMenu), pIcon, pContainer);
96 r = TRUE;
97 }
89
90 cd_satus_notifier_build_item_dbusmenu (pItem);
91 if (pItem->pMenu != NULL)
92 {
93 cairo_dock_popup_menu_on_icon (GTK_WIDGET (pItem->pMenu), pIcon, pContainer);
94 r = TRUE;
9895 }
9996
10097 if (!r) // no menu available, send the corresponding action
3535 gboolean cd_status_notifier_on_enter_icon (CairoDockModuleInstance *myApplet, Icon *pIcon, CairoDock *pDock, gboolean *bStartAnimation);
3636
3737
38 gboolean on_draw_menu_reposition (GtkWidget *pWidget, G_GNUC_UNUSED gpointer useless, gpointer data);
39
3840 gboolean on_mouse_moved (CairoDockModuleInstance *myApplet, CairoContainer *pContainer, gboolean *bStartAnimation);
3941
4042 gboolean on_update_desklet (CairoDockModuleInstance *myApplet, CairoContainer *pContainer, gboolean *bContinueAnimation);
9898 gboolean bInvalid; // item deja en cours de destruction
9999 DbusmenuGtkMenu *pMenu;
100100 cairo_surface_t *pSurface;
101 guint iSidUpdateIcon;
102 // menu redraw
103 int iMenuWidth;
101104 } CDStatusNotifierItem;
102105
103106
3030 bus_iface_str = 'org.kde.StatusNotifierWatcher'
3131 items_list = [] # array of service+path
3232 hosts_list = [] # array of services
33
34 def _emit_host_registered (self):
35 self.StatusNotifierHostRegistered()
36 return False
3337
3438 def __init__(self):
3539 DBusGMainLoop(set_as_default=True)
7377 for it in to_be_removed:
7478 self.hosts_list.remove (it)
7579 self.StatusNotifierHostUnregistered()
80 elif (service == 'com.Skype.API'): # this stupid proprietary software only creates its item when the host appears !
81 glib.timeout_add_seconds(2, self._emit_host_registered)
7682
7783 ### methods ###
7884
111117 return self.items_list
112118 else: # too bad! dbus-python can't encode the GValue if 'items_list' is None or [].
113119 return [''] # so we return a empty string; hopefuly the host will skip this invalid value.
114 elif property == 'HasStatusNotifierHostRegistered':
120 elif property == 'IsStatusNotifierHostRegistered':
121 return (len (self.hosts_list) != 0)
122 elif property == 'HasStatusNotifierHostRegistered': # deprecated
115123 return (len (self.hosts_list) != 0)
116124 elif property == 'ProtocolVersion':
117125 return 0
4848 pInterface->save_custom_widget = cd_clock_save_custom_widget;
4949 CD_APPLET_DEFINE_END
5050
51 static gboolean _cd_check_new_minute (CairoDockModuleInstance *myApplet)
52 {
53 myData.iSidUpdateClock = g_timeout_add_seconds (60,
54 (GSourceFunc) cd_clock_update_with_time,
55 (gpointer) myApplet); // this new g_timeout should start approximately at 00" (between 00" and 01" ; better than between [00-60])
56 cd_clock_update_with_time (myApplet); // update the time right now and not after 60sec
57 return FALSE;
58 }
59
60 static void _cd_launch_timer (CairoDockModuleInstance *myApplet)
61 {
62 cd_clock_update_with_time (myApplet); // should update myData.currentTime
63
64 if (! myConfig.bShowSeconds) // can be interesting to show the correct minute... Start the new timer with a delay
65 {
66 guint iWaitSeconds = 60 - myData.currentTime.tm_sec;
67 cd_debug ("Waiting for a new minute during %d sec", iWaitSeconds);
68
69 myData.iSidUpdateClock = g_timeout_add_seconds (iWaitSeconds,
70 (GSourceFunc) _cd_check_new_minute,
71 (gpointer) myApplet);
72 }
73 else
74 myData.iSidUpdateClock = g_timeout_add_seconds (1, (GSourceFunc) cd_clock_update_with_time, (gpointer) myApplet);
75 }
5176
5277 CD_APPLET_INIT_BEGIN
5378 if (myDesklet)
95120 cd_clock_list_tasks (myApplet);
96121
97122 //\_______________ On lance le timer.
98 if (! myConfig.bShowSeconds) // pour ne pas attendre 1 mn avant d'avoir le dessin.
99 cd_clock_update_with_time (myApplet);
100 myData.iSidUpdateClock = g_timeout_add_seconds ((myConfig.bShowSeconds ? 1: 60), (GSourceFunc) cd_clock_update_with_time, (gpointer) myApplet);
123 _cd_launch_timer (myApplet);
101124 CD_APPLET_INIT_END
102125
103126
165188 myData.iLastCheckedDay = -1;
166189 myData.iLastCheckedMonth = -1;
167190 myData.iLastCheckedYear = -1;
168 cd_clock_update_with_time (myApplet);
169 myData.iSidUpdateClock = g_timeout_add_seconds ((myConfig.bShowSeconds ? 1: 60), (GSourceFunc) cd_clock_update_with_time, (gpointer) myApplet);
191 _cd_launch_timer (myApplet);
170192 }
171193 else
172194 {
5353 static inline void _fill_handler_properties (const gchar *cDesktopFileName, gchar *cAppClass)
5454 {
5555 g_free ((gchar*)myData.pCurrentHandler->appclass);
56 if (cAppClass == NULL) // cAppClass: this parameter is optional
57 myData.pCurrentHandler->appclass = cairo_dock_register_class (cDesktopFileName);
58 else
59 myData.pCurrentHandler->appclass = cAppClass;
56 myData.pCurrentHandler->appclass = cAppClass;
6057 g_free ((gchar*)myData.pCurrentHandler->launch);
6158 myData.pCurrentHandler->launch = g_strdup (cairo_dock_get_class_command (myData.pCurrentHandler->appclass));
6259 if (myData.pCurrentHandler->launch == NULL) // we really need a command to launch it on click, so insist a little
63 {
6460 myData.pCurrentHandler->launch = g_strdup (cDesktopFileName);
65 }
6661 g_free ((gchar*)myData.pCurrentHandler->cDisplayedName);
6762 myData.pCurrentHandler->cDisplayedName = g_strdup (cairo_dock_get_class_name (myData.pCurrentHandler->appclass));
63 }
64
65 static inline void _get_right_class_and_desktop_file (const gchar *cName, gchar **cDesktopFileName, gchar **cAppClass)
66 {
67 if (myConfig.cLastKnownDesktopFile)
68 {
69 *cDesktopFileName = myConfig.cLastKnownDesktopFile;
70 *cAppClass = cairo_dock_register_class (*cDesktopFileName); // no need to be freed here
71 }
72 if (*cAppClass == NULL && cName) // myConfig.cLastKnownDesktopFile is NULL when transitionning from an old version of the applet where we didn't use the "Desktop Entry" property yet -> use some heuristic as a fallback.
73 {
74 *cAppClass = cairo_dock_register_class (cName); // no need to be freed here
75 if (*cAppClass == NULL &&
76 (*cDesktopFileName = strrchr (cName, '.')) != NULL) // if cName = org.mpris.MediaPlayer2.amarok => amarok
77 *cAppClass = cairo_dock_register_class (*cDesktopFileName+1); // no need to be freed here
78 else
79 *cDesktopFileName = (gchar *)cName;
80 }
81 cd_debug ("%s (%s - %s) => (%s - %s)", __func__, myConfig.cLastKnownDesktopFile, cName, *cDesktopFileName, *cAppClass);
6882 }
6983
7084 MusicPlayerHandler *cd_musicplayer_get_handler_by_name (const gchar *cName)
361375 myData.pCurrentHandler = cd_musicplayer_get_handler_by_name ("Mpris2"); // no need to watch it, it was already done (that's why we are here !)
362376
363377 // fill its properties
364 myData.pCurrentHandler->appclass = cairo_dock_register_class (myConfig.cLastKnownDesktopFile ? myConfig.cLastKnownDesktopFile : cName); // myConfig.cLastKnownDesktopFile is NULL when transitionning from an old version of the applet where we didn't use the "Desktop Entry" property yet -> use some heuristic as a fallback.
365 myData.pCurrentHandler->launch = g_strdup (cairo_dock_get_class_command (myData.pCurrentHandler->appclass));
366 myData.pCurrentHandler->cDisplayedName = g_strdup (cairo_dock_get_class_name (myData.pCurrentHandler->appclass));
367 if (myData.pCurrentHandler->launch == NULL) // we really need a command to launch it on click, so insist a little
368 {
369 myData.pCurrentHandler->launch = g_strdup (cName);
370 }
371
378 gchar *cAppClass = NULL, *cDesktopFileName = NULL;
379 _get_right_class_and_desktop_file (cName, &cDesktopFileName, &cAppClass);
380 if (cAppClass) // better to not use any class than a wrong class
381 _fill_handler_properties (cDesktopFileName, cAppClass);
382
372383 g_free ((gchar*)myData.pCurrentHandler->cMprisService);
373384 myData.pCurrentHandler->cMprisService = g_strdup (cName);
374385 }
487498 // get the MPRIS2 handler
488499 myData.pCurrentHandler = cd_musicplayer_get_handler_by_name ("Mpris2");
489500
490 // fill its properties
491 /* myConfig.cLastKnownDesktopFile is NULL when transitionning from an
492 * old version of the applet where we didn't use the "Desktop Entry"
493 * property yet -> use some heuristic as a fallback.
494 */
495 _fill_handler_properties (myConfig.cLastKnownDesktopFile ? myConfig.cLastKnownDesktopFile : cName, NULL);
501 gchar *cAppClass = NULL, *cDesktopFileName = NULL;
502 _get_right_class_and_desktop_file (cName, &cDesktopFileName, &cAppClass);
503 if (cAppClass) // better to not use any class than a wrong class
504 _fill_handler_properties (cDesktopFileName, cAppClass);
496505
497506 myData.pCurrentHandler->cMprisService = g_strdup_printf (CD_MPRIS2_SERVICE_BASE".%s", cName);
498507 myData.cMpris2Service = NULL;