1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <math.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <cairo.h>
26
27 #include "cairo-dock-icon-factory.h"
28 #include "cairo-dock-icon-facility.h"
29 #include "cairo-dock-surface-factory.h"
30 #include "cairo-dock-log.h"
31 #include "cairo-dock-utils.h" // cairo_dock_remove_version_from_string
32 #include "cairo-dock-dock-manager.h"
33 #include "cairo-dock-applet-manager.h"
34 #include "cairo-dock-launcher-manager.h"
35 #include "cairo-dock-stack-icon-manager.h"
36 #include "cairo-dock-separator-manager.h"
37 #include "cairo-dock-class-icon-manager.h"
38 #include "cairo-dock-dock-factory.h"
39 #include "cairo-dock-desktop-manager.h" // gldi_desktop_notify_startup
40 #include "cairo-dock-module-manager.h" // GldiModule
41 #include "cairo-dock-module-instance-manager.h" // GldiModuleInstance
42 #include "cairo-dock-dock-facility.h"
43 #include "cairo-dock-applications-manager.h"
44 #include "cairo-dock-draw.h"
45 #include "cairo-dock-image-buffer.h"
46 #include "cairo-dock-icon-manager.h"
47 #include "cairo-dock-indicator-manager.h" // myIndicatorsParam.bUseClassIndic
48 #include "cairo-dock-container.h"
49 #include "cairo-dock-animations.h"
50 #include "cairo-dock-application-facility.h"
51 #include "cairo-dock-keyfile-utilities.h"
52 #include "cairo-dock-file-manager.h"
53 #include "cairo-dock-windows-manager.h"
54 #include "cairo-dock-class-manager.h"
55
56 extern CairoDock *g_pMainDock;
57 extern CairoDockDesktopEnv g_iDesktopEnv;
58
59 static GHashTable *s_hClassTable = NULL;
60
61
cairo_dock_free_class_appli(CairoDockClassAppli * pClassAppli)62 static void cairo_dock_free_class_appli (CairoDockClassAppli *pClassAppli)
63 {
64 g_list_free (pClassAppli->pIconsOfClass);
65 g_list_free (pClassAppli->pAppliOfClass);
66 g_free (pClassAppli->cDesktopFile);
67 g_free (pClassAppli->cCommand);
68 g_free (pClassAppli->cName);
69 g_free (pClassAppli->cIcon);
70 g_free (pClassAppli->cStartupWMClass);
71 g_free (pClassAppli->cWorkingDirectory);
72 if (pClassAppli->pMimeTypes)
73 g_strfreev (pClassAppli->pMimeTypes);
74 g_list_foreach (pClassAppli->pMenuItems, (GFunc)g_strfreev, NULL);
75 g_list_free (pClassAppli->pMenuItems);
76 if (pClassAppli->iSidOpeningTimeout != 0)
77 g_source_remove (pClassAppli->iSidOpeningTimeout);
78 g_free (pClassAppli);
79 }
80
_cairo_dock_lookup_class_appli(const gchar * cClass)81 static inline CairoDockClassAppli *_cairo_dock_lookup_class_appli (const gchar *cClass)
82 {
83 return (cClass != NULL ? g_hash_table_lookup (s_hClassTable, cClass) : NULL);
84 }
85
86
_on_window_created(G_GNUC_UNUSED gpointer data,GldiWindowActor * actor)87 static gboolean _on_window_created (G_GNUC_UNUSED gpointer data, GldiWindowActor *actor)
88 {
89 gldi_class_startup_notify_end (actor->cClass);
90
91 return GLDI_NOTIFICATION_LET_PASS;
92 }
_on_window_activated(G_GNUC_UNUSED gpointer data,GldiWindowActor * actor)93 static gboolean _on_window_activated (G_GNUC_UNUSED gpointer data, GldiWindowActor *actor)
94 {
95 if (! actor)
96 return GLDI_NOTIFICATION_LET_PASS;
97
98 gldi_class_startup_notify_end (actor->cClass);
99
100 return GLDI_NOTIFICATION_LET_PASS;
101 }
cairo_dock_initialize_class_manager(void)102 void cairo_dock_initialize_class_manager (void)
103 {
104 if (s_hClassTable == NULL)
105 s_hClassTable = g_hash_table_new_full (g_str_hash,
106 g_str_equal,
107 g_free,
108 (GDestroyNotify) cairo_dock_free_class_appli);
109 // register to events to detect the ending of a launching
110 gldi_object_register_notification (&myWindowObjectMgr,
111 NOTIFICATION_WINDOW_CREATED,
112 (GldiNotificationFunc) _on_window_created,
113 GLDI_RUN_AFTER, NULL);
114 gldi_object_register_notification (&myWindowObjectMgr,
115 NOTIFICATION_WINDOW_ACTIVATED,
116 (GldiNotificationFunc) _on_window_activated,
117 GLDI_RUN_AFTER, NULL); // some applications don't open a new window, but rather take the focus;
118 }
119
120
cairo_dock_list_existing_appli_with_class(const gchar * cClass)121 const GList *cairo_dock_list_existing_appli_with_class (const gchar *cClass)
122 {
123 g_return_val_if_fail (cClass != NULL, NULL);
124
125 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
126 return (pClassAppli != NULL ? pClassAppli->pAppliOfClass : NULL);
127 }
128
129
cairo_dock_get_class(const gchar * cClass)130 static CairoDockClassAppli *cairo_dock_get_class (const gchar *cClass)
131 {
132 g_return_val_if_fail (cClass != NULL, NULL);
133
134 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
135 if (pClassAppli == NULL)
136 {
137 pClassAppli = g_new0 (CairoDockClassAppli, 1);
138 g_hash_table_insert (s_hClassTable, g_strdup (cClass), pClassAppli);
139 }
140 return pClassAppli;
141 }
142
_cairo_dock_add_inhibitor_to_class(const gchar * cClass,Icon * pIcon)143 static gboolean _cairo_dock_add_inhibitor_to_class (const gchar *cClass, Icon *pIcon)
144 {
145 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
146 g_return_val_if_fail (pClassAppli!= NULL, FALSE);
147
148 g_return_val_if_fail (g_list_find (pClassAppli->pIconsOfClass, pIcon) == NULL, TRUE);
149 pClassAppli->pIconsOfClass = g_list_prepend (pClassAppli->pIconsOfClass, pIcon);
150
151 return TRUE;
152 }
153
cairo_dock_get_class_subdock(const gchar * cClass)154 CairoDock *cairo_dock_get_class_subdock (const gchar *cClass)
155 {
156 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
157 g_return_val_if_fail (pClassAppli!= NULL, NULL);
158
159 return gldi_dock_get (pClassAppli->cDockName);
160 }
161
cairo_dock_create_class_subdock(const gchar * cClass,CairoDock * pParentDock)162 CairoDock* cairo_dock_create_class_subdock (const gchar *cClass, CairoDock *pParentDock)
163 {
164 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
165 g_return_val_if_fail (pClassAppli!= NULL, NULL);
166
167 CairoDock *pDock = gldi_dock_get (pClassAppli->cDockName);
168 if (pDock == NULL) // cDockName not yet defined, or previous class subdock no longer exists
169 {
170 g_free (pClassAppli->cDockName);
171 pClassAppli->cDockName = cairo_dock_get_unique_dock_name (cClass);
172 pDock = gldi_subdock_new (pClassAppli->cDockName, NULL, pParentDock, NULL);
173 }
174
175 return pDock;
176 }
177
cairo_dock_destroy_class_subdock(const gchar * cClass)178 static void cairo_dock_destroy_class_subdock (const gchar *cClass)
179 {
180 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
181 g_return_if_fail (pClassAppli!= NULL);
182
183 CairoDock *pDock = gldi_dock_get (pClassAppli->cDockName);
184 if (pDock)
185 {
186 gldi_object_unref (GLDI_OBJECT(pDock));
187 }
188
189 g_free (pClassAppli->cDockName);
190 pClassAppli->cDockName = NULL;
191 }
192
cairo_dock_add_appli_icon_to_class(Icon * pIcon)193 gboolean cairo_dock_add_appli_icon_to_class (Icon *pIcon)
194 {
195 g_return_val_if_fail (CAIRO_DOCK_ICON_TYPE_IS_APPLI (pIcon) && pIcon->pAppli, FALSE);
196 cd_debug ("%s (%s)", __func__, pIcon->cClass);
197
198 if (pIcon->cClass == NULL)
199 {
200 cd_message (" %s doesn't have any class, not good!", pIcon->cName);
201 return FALSE;
202 }
203 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
204 g_return_val_if_fail (pClassAppli!= NULL, FALSE);
205
206 ///if (pClassAppli->iAge == 0) // age is > 0, so it means we have never set it yet.
207 if (pClassAppli->pAppliOfClass == NULL) // the first appli of a class defines the age of the class.
208 pClassAppli->iAge = pIcon->pAppli->iAge;
209
210 g_return_val_if_fail (g_list_find (pClassAppli->pAppliOfClass, pIcon) == NULL, TRUE);
211 pClassAppli->pAppliOfClass = g_list_prepend (pClassAppli->pAppliOfClass, pIcon);
212
213 return TRUE;
214 }
215
cairo_dock_remove_appli_from_class(Icon * pIcon)216 gboolean cairo_dock_remove_appli_from_class (Icon *pIcon)
217 {
218 g_return_val_if_fail (pIcon!= NULL, FALSE);
219 cd_debug ("%s (%s, %s)", __func__, pIcon->cClass, pIcon->cName);
220
221 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
222 g_return_val_if_fail (pClassAppli!= NULL, FALSE);
223
224 pClassAppli->pAppliOfClass = g_list_remove (pClassAppli->pAppliOfClass, pIcon);
225
226 return TRUE;
227 }
228
cairo_dock_set_class_use_xicon(const gchar * cClass,gboolean bUseXIcon)229 gboolean cairo_dock_set_class_use_xicon (const gchar *cClass, gboolean bUseXIcon)
230 {
231 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
232 g_return_val_if_fail (pClassAppli!= NULL, FALSE);
233
234 if (pClassAppli->bUseXIcon == bUseXIcon) // nothing to do.
235 return FALSE;
236
237 GList *pElement;
238 Icon *pAppliIcon;
239 for (pElement = pClassAppli->pAppliOfClass; pElement != NULL; pElement = pElement->next)
240 {
241 pAppliIcon = pElement->data;
242 if (bUseXIcon)
243 {
244 cd_message ("%s: take X icon", pAppliIcon->cName);
245 }
246 else
247 {
248 cd_message ("%s: doesn't use X icon", pAppliIcon->cName);
249 }
250
251 cairo_dock_reload_icon_image (pAppliIcon, cairo_dock_get_icon_container (pAppliIcon));
252 }
253
254 return TRUE;
255 }
256
257
_cairo_dock_set_same_indicator_on_sub_dock(Icon * pInhibhatorIcon)258 static void _cairo_dock_set_same_indicator_on_sub_dock (Icon *pInhibhatorIcon)
259 {
260 CairoDock *pInhibatorDock = CAIRO_DOCK(cairo_dock_get_icon_container (pInhibhatorIcon));
261 if (GLDI_OBJECT_IS_DOCK(pInhibatorDock) && pInhibatorDock->iRefCount > 0) // the inhibitor is in a sub-dock.
262 {
263 gboolean bSubDockHasIndicator = FALSE;
264 if (pInhibhatorIcon->bHasIndicator)
265 {
266 bSubDockHasIndicator = TRUE;
267 }
268 else
269 {
270 GList* ic;
271 Icon *icon;
272 for (ic = pInhibatorDock->icons ; ic != NULL; ic = ic->next)
273 {
274 icon = ic->data;
275 if (icon->bHasIndicator)
276 {
277 bSubDockHasIndicator = TRUE;
278 break;
279 }
280 }
281 }
282 CairoDock *pParentDock = NULL;
283 Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pInhibatorDock, &pParentDock);
284 if (pPointingIcon != NULL && pPointingIcon->bHasIndicator != bSubDockHasIndicator)
285 {
286 cd_message (" for the sub-dock %s : indicator <- %d", pPointingIcon->cName, bSubDockHasIndicator);
287 pPointingIcon->bHasIndicator = bSubDockHasIndicator;
288 if (pParentDock != NULL)
289 cairo_dock_redraw_icon (pPointingIcon);
290 }
291 }
292 }
293
_gldi_appli_icon_detach_of_class(const gchar * cClass)294 static GldiWindowActor *_gldi_appli_icon_detach_of_class (const gchar *cClass)
295 {
296 g_return_val_if_fail (cClass != NULL, 0);
297
298 const GList *pList = cairo_dock_list_existing_appli_with_class (cClass);
299 Icon *pIcon;
300 const GList *pElement;
301 ///gboolean bNeedsRedraw = FALSE;
302 CairoDock *pParentDock;
303 GldiWindowActor *pFirstFoundActor = NULL;
304 for (pElement = pList; pElement != NULL; pElement = pElement->next)
305 {
306 pIcon = pElement->data;
307 pParentDock = CAIRO_DOCK(cairo_dock_get_icon_container (pIcon));
308 if (pParentDock == NULL) // not in a dock => nothing to do.
309 continue;
310
311 cd_debug ("detachment of the icon %s (%p)", pIcon->cName, pFirstFoundActor);
312 gldi_icon_detach (pIcon);
313
314 // if the icon was in the class sub-dock, check if it became empty
315 if (pParentDock == cairo_dock_get_class_subdock (cClass)) // the icon was in the class sub-dock
316 {
317 if (pParentDock->icons == NULL) // and it's now empty -> destroy it (and the class-icon pointing on it as well)
318 {
319 CairoDock *pMainDock = NULL;
320 Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pParentDock, &pMainDock);
321 /// TODO: register to the destroy event of the class sub-dock...
322 cairo_dock_destroy_class_subdock (cClass); // destroy it before the class-icon, since it will destroy the sub-dock
323 if (pMainDock && CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (pPointingIcon))
324 {
325 gldi_icon_detach (pPointingIcon);
326 gldi_object_unref (GLDI_OBJECT(pPointingIcon));
327 }
328 }
329 }
330
331 if (pFirstFoundActor == NULL) // we grab the 1st app of this class.
332 {
333 pFirstFoundActor = pIcon->pAppli;
334 }
335 }
336 return pFirstFoundActor;
337 }
cairo_dock_inhibite_class(const gchar * cClass,Icon * pInhibitorIcon)338 gboolean cairo_dock_inhibite_class (const gchar *cClass, Icon *pInhibitorIcon)
339 {
340 g_return_val_if_fail (cClass != NULL, FALSE);
341 cd_message ("%s (%s)", __func__, cClass);
342
343 // add inhibitor to class (first, so that applis can find it and take its surface if necessary)
344 if (! _cairo_dock_add_inhibitor_to_class (cClass, pInhibitorIcon))
345 return FALSE;
346
347 // set class name on the inhibitor if not already done.
348 if (pInhibitorIcon && pInhibitorIcon->cClass != cClass)
349 {
350 g_free (pInhibitorIcon->cClass);
351 pInhibitorIcon->cClass = g_strdup (cClass);
352 }
353
354 // if launchers are mixed with applis, steal applis icons.
355 if (!myTaskbarParam.bMixLauncherAppli)
356 return TRUE;
357 GldiWindowActor *pFirstFoundActor = _gldi_appli_icon_detach_of_class (cClass); // detach existing applis, and then retach them to the inhibitor.
358 if (pInhibitorIcon != NULL)
359 {
360 // inhibitor takes control of the first existing appli of the class.
361 gldi_icon_set_appli (pInhibitorIcon, pFirstFoundActor);
362 pInhibitorIcon->bHasIndicator = (pFirstFoundActor != NULL);
363 _cairo_dock_set_same_indicator_on_sub_dock (pInhibitorIcon);
364
365 // other applis icons are retached to the inhibitor.
366 const GList *pList = cairo_dock_list_existing_appli_with_class (cClass);
367 Icon *pIcon;
368 const GList *pElement;
369 for (pElement = pList; pElement != NULL; pElement = pElement->next)
370 {
371 pIcon = pElement->data;
372 cd_debug (" an app is detached (%s)", pIcon->cName);
373 if (pIcon->pAppli != pFirstFoundActor && cairo_dock_get_icon_container (pIcon) == NULL) // detached and has to be re-attached.
374 gldi_appli_icon_insert_in_dock (pIcon, g_pMainDock, ! CAIRO_DOCK_ANIMATE_ICON);
375 }
376 }
377
378 return TRUE;
379 }
380
cairo_dock_class_is_inhibited(const gchar * cClass)381 gboolean cairo_dock_class_is_inhibited (const gchar *cClass)
382 {
383 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
384 return (pClassAppli != NULL && pClassAppli->pIconsOfClass != NULL);
385 }
386
cairo_dock_class_is_using_xicon(const gchar * cClass)387 gboolean cairo_dock_class_is_using_xicon (const gchar *cClass)
388 {
389 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
390 // if pClassAppli == NULL, there is no launcher able to give its icon but we can found one in icons theme of the system.
391 return (pClassAppli != NULL && pClassAppli->bUseXIcon);
392 }
393
cairo_dock_class_is_expanded(const gchar * cClass)394 gboolean cairo_dock_class_is_expanded (const gchar *cClass)
395 {
396 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
397 return (pClassAppli != NULL && pClassAppli->bExpand);
398 }
399
cairo_dock_prevent_inhibited_class(Icon * pIcon)400 gboolean cairo_dock_prevent_inhibited_class (Icon *pIcon)
401 {
402 g_return_val_if_fail (pIcon != NULL, FALSE);
403 //g_print ("%s (%s)\n", __func__, pIcon->cClass);
404
405 gboolean bToBeInhibited = FALSE;
406 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (pIcon->cClass);
407 if (pClassAppli != NULL)
408 {
409 Icon *pInhibitorIcon;
410 GList *pElement;
411 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
412 {
413 pInhibitorIcon = pElement->data;
414 if (pInhibitorIcon != NULL) // an inhibitor is present.
415 {
416 if (pInhibitorIcon->pAppli == NULL && pInhibitorIcon->pSubDock == NULL) // this icon inhibits this class but doesn't control any apps yet
417 {
418 gldi_icon_set_appli (pInhibitorIcon, pIcon->pAppli);
419 cd_message (">>> %s will take an indicator during the next redraw ! (pAppli : %p)", pInhibitorIcon->cName, pInhibitorIcon->pAppli);
420 pInhibitorIcon->bHasIndicator = TRUE;
421 _cairo_dock_set_same_indicator_on_sub_dock (pInhibitorIcon);
422 /**}
423
424 if (pInhibitorIcon->pAppli == pIcon->pAppli) // this icon controls us.
425 {*/
426 CairoDock *pInhibatorDock = CAIRO_DOCK(cairo_dock_get_icon_container (pInhibitorIcon));
427 //\______________ We place the icon for X.
428 if (! bToBeInhibited) // we put the thumbnail only on the 1st one.
429 {
430 if (pInhibatorDock != NULL)
431 {
432 //g_print ("we move the thumbnail on the inhibitor %s\n", pInhibitorIcon->cName);
433 gldi_appli_icon_set_geometry_for_window_manager (pInhibitorIcon, pInhibatorDock);
434 }
435 }
436 //\______________ We update inhibitor's label.
437 if (pInhibatorDock != NULL && pIcon->cName != NULL)
438 {
439 if (pInhibitorIcon->cInitialName == NULL)
440 pInhibitorIcon->cInitialName = pInhibitorIcon->cName;
441 else
442 g_free (pInhibitorIcon->cName);
443 pInhibitorIcon->cName = NULL;
444 gldi_icon_set_name (pInhibitorIcon, pIcon->cName);
445 }
446 }
447 bToBeInhibited = (pInhibitorIcon->pAppli == pIcon->pAppli);
448 }
449 }
450 }
451 return bToBeInhibited;
452 }
453
454
_cairo_dock_remove_icon_from_class(Icon * pInhibitorIcon)455 static void _cairo_dock_remove_icon_from_class (Icon *pInhibitorIcon)
456 {
457 g_return_if_fail (pInhibitorIcon != NULL);
458 cd_message ("%s (%s)", __func__, pInhibitorIcon->cClass);
459
460 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (pInhibitorIcon->cClass);
461 if (pClassAppli != NULL)
462 {
463 pClassAppli->pIconsOfClass = g_list_remove (pClassAppli->pIconsOfClass, pInhibitorIcon);
464 }
465 }
466
cairo_dock_deinhibite_class(const gchar * cClass,Icon * pInhibitorIcon)467 void cairo_dock_deinhibite_class (const gchar *cClass, Icon *pInhibitorIcon)
468 {
469 cd_message ("%s (%s)", __func__, cClass);
470 _cairo_dock_remove_icon_from_class (pInhibitorIcon);
471
472 if (pInhibitorIcon != NULL && pInhibitorIcon->pSubDock != NULL && pInhibitorIcon->pSubDock == cairo_dock_get_class_subdock (cClass)) // the launcher is controlling several appli icons, place them back in the taskbar.
473 {
474 // first destroy the class sub-dock, so that the appli icons won't go inside again.
475 // we empty the sub-dock then destroy it, then re-insert the appli icons
476 GList *icons = pInhibitorIcon->pSubDock->icons;
477 pInhibitorIcon->pSubDock->icons = NULL; // empty the sub-dock
478 cairo_dock_destroy_class_subdock (cClass); // destroy the sub-dock without destroying its icons
479 pInhibitorIcon->pSubDock = NULL; // since the inhibitor can already be detached, the sub-dock can't find it
480
481 Icon *pAppliIcon;
482 GList *ic;
483 for (ic = icons; ic != NULL; ic = ic->next)
484 {
485 pAppliIcon = ic->data;
486 cairo_dock_set_icon_container (pAppliIcon, NULL); // manually "detach" it
487 }
488
489 // then re-insert the appli icons.
490 for (ic = icons; ic != NULL; ic = ic->next)
491 {
492 pAppliIcon = ic->data;
493 gldi_appli_icon_insert_in_dock (pAppliIcon, g_pMainDock, ! CAIRO_DOCK_ANIMATE_ICON);
494 }
495 g_list_free (icons);
496
497 cairo_dock_trigger_load_icon_buffers (pInhibitorIcon); // in case the inhibitor was drawn with an emblem or a stack of the applis
498 }
499
500 if (pInhibitorIcon == NULL || pInhibitorIcon->pAppli != NULL) // the launcher is controlling 1 appli icon, or we deinhibate all the inhibitors.
501 {
502 const GList *pList = cairo_dock_list_existing_appli_with_class (cClass);
503 Icon *pIcon;
504 ///gboolean bNeedsRedraw = FALSE;
505 ///CairoDock *pParentDock;
506 const GList *pElement;
507 for (pElement = pList; pElement != NULL; pElement = pElement->next)
508 {
509 pIcon = pElement->data;
510 if (pInhibitorIcon == NULL || pIcon->pAppli == pInhibitorIcon->pAppli)
511 {
512 cd_message ("re-add the icon previously inhibited (pAppli:%p)", pIcon->pAppli);
513 pIcon->fInsertRemoveFactor = 0;
514 pIcon->fScale = 1.;
515 /**pParentDock = */
516 gldi_appli_icon_insert_in_dock (pIcon, g_pMainDock, ! CAIRO_DOCK_ANIMATE_ICON);
517 ///bNeedsRedraw = (pParentDock != NULL && pParentDock->bIsMainDock);
518 }
519 ///cairo_dock_reload_icon_image (pIcon, cairo_dock_get_icon_container (pIcon)); /// question : why should we do that for all icons?...
520 }
521 ///if (bNeedsRedraw)
522 /// gtk_widget_queue_draw (g_pMainDock->container.pWidget); /// pDock->pRenderer->calculate_icons (pDock); ?...
523 }
524 if (pInhibitorIcon != NULL)
525 {
526 cd_message (" the inhibitor has lost everything");
527 gldi_icon_unset_appli (pInhibitorIcon);
528 pInhibitorIcon->bHasIndicator = FALSE;
529 g_free (pInhibitorIcon->cClass);
530 pInhibitorIcon->cClass = NULL;
531 cd_debug (" no more classes");
532 }
533 }
534
535
gldi_window_detach_from_inhibitors(GldiWindowActor * pAppli)536 void gldi_window_detach_from_inhibitors (GldiWindowActor *pAppli)
537 {
538 const gchar *cClass = pAppli->cClass;
539 cd_message ("%s (%s)", __func__, cClass);
540 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
541 if (pClassAppli != NULL)
542 {
543 GldiWindowActor *pNextAppli = NULL; // next window that will be inhibited.
544 gboolean bFirstSearch = TRUE;
545 Icon *pSameClassIcon = NULL;
546 Icon *pIcon;
547 GList *pElement;
548 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
549 {
550 pIcon = pElement->data;
551 if (pIcon->pAppli == pAppli) // this inhibitor controls the given window -> make it control another (possibly none).
552 {
553 // find the next inhibited appli
554 if (bFirstSearch) // we didn't search the next window yet, do it now.
555 {
556 bFirstSearch = FALSE;
557 Icon *pOneIcon;
558 GList *ic;
559 for (ic = g_list_last (pClassAppli->pAppliOfClass); ic != NULL; ic = ic->prev) // reverse order, to take the oldest window of this class.
560 {
561 pOneIcon = ic->data;
562 if (pOneIcon != NULL
563 && pOneIcon->pAppli != NULL
564 && pOneIcon->pAppli != pAppli // not the window we precisely want to avoid
565 && (! myTaskbarParam.bAppliOnCurrentDesktopOnly || gldi_window_is_on_current_desktop (pOneIcon->pAppli))) // can actually be displayed
566 {
567 pSameClassIcon = pOneIcon;
568 break ;
569 }
570 }
571 pNextAppli = (pSameClassIcon != NULL ? pSameClassIcon->pAppli : NULL);
572 if (pSameClassIcon != NULL) // this icon will be inhibited, we need to detach it if needed
573 {
574 cd_message (" it's %s which will replace it", pSameClassIcon->cName);
575 gldi_icon_detach (pSameClassIcon); // it can't be the class sub-dock, because pIcon had the window actor, so it doesn't hold the class sub-dock and the class is not grouped (otherwise they would all be in the class sub-dock).
576 }
577 }
578
579 // make the icon inhibits the next appli (possibly none)
580 gldi_icon_set_appli (pIcon, pNextAppli);
581 pIcon->bHasIndicator = (pNextAppli != NULL);
582 _cairo_dock_set_same_indicator_on_sub_dock (pIcon);
583 if (pNextAppli == NULL)
584 gldi_icon_set_name (pIcon, pIcon->cInitialName);
585 cd_message (" %s : bHasIndicator <- %d, pAppli <- %p", pIcon->cName, pIcon->bHasIndicator, pIcon->pAppli);
586
587 // redraw
588 GldiContainer *pContainer = cairo_dock_get_icon_container (pIcon);
589 if (pContainer)
590 gtk_widget_queue_draw (pContainer->pWidget);
591 }
592 }
593 }
594 }
595
_cairo_dock_remove_all_applis_from_class(G_GNUC_UNUSED gchar * cClass,CairoDockClassAppli * pClassAppli,G_GNUC_UNUSED gpointer data)596 static void _cairo_dock_remove_all_applis_from_class (G_GNUC_UNUSED gchar *cClass, CairoDockClassAppli *pClassAppli, G_GNUC_UNUSED gpointer data)
597 {
598 g_list_free (pClassAppli->pAppliOfClass);
599 pClassAppli->pAppliOfClass = NULL;
600
601 Icon *pInhibitorIcon;
602 GList *pElement;
603 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
604 {
605 pInhibitorIcon = pElement->data;
606 pInhibitorIcon->bHasIndicator = FALSE;
607 gldi_icon_unset_appli (pInhibitorIcon);
608 _cairo_dock_set_same_indicator_on_sub_dock (pInhibitorIcon);
609 }
610 }
cairo_dock_remove_all_applis_from_class_table(void)611 void cairo_dock_remove_all_applis_from_class_table (void) // for the stop_application_manager
612 {
613 g_hash_table_foreach (s_hClassTable, (GHFunc) _cairo_dock_remove_all_applis_from_class, NULL);
614 }
615
cairo_dock_reset_class_table(void)616 void cairo_dock_reset_class_table (void)
617 {
618 g_hash_table_remove_all (s_hClassTable);
619 }
620
621
cairo_dock_create_surface_from_class(const gchar * cClass,int iWidth,int iHeight)622 cairo_surface_t *cairo_dock_create_surface_from_class (const gchar *cClass, int iWidth, int iHeight)
623 {
624 cd_debug ("%s (%s)", __func__, cClass);
625 // first we try to get an icon from one of the inhibitor.
626 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
627 if (pClassAppli != NULL)
628 {
629 cd_debug ("bUseXIcon:%d", pClassAppli->bUseXIcon);
630 if (pClassAppli->bUseXIcon)
631 return NULL;
632
633 GList *pElement;
634 Icon *pInhibitorIcon;
635 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
636 {
637 pInhibitorIcon = pElement->data;
638 cd_debug (" %s", pInhibitorIcon->cName);
639 if (! CAIRO_DOCK_ICON_TYPE_IS_APPLET (pInhibitorIcon))
640 {
641 if (pInhibitorIcon->pSubDock == NULL || myIndicatorsParam.bUseClassIndic) // in the case where a launcher has more than one instance of its class and which represents the stack, we doesn't take the icon.
642 {
643 cd_debug ("%s will give its surface", pInhibitorIcon->cName);
644 return cairo_dock_duplicate_surface (pInhibitorIcon->image.pSurface,
645 pInhibitorIcon->image.iWidth,
646 pInhibitorIcon->image.iHeight,
647 iWidth,
648 iHeight);
649 }
650 else if (pInhibitorIcon->cFileName != NULL)
651 {
652 gchar *cIconFilePath = cairo_dock_search_icon_s_path (pInhibitorIcon->cFileName, MAX (iWidth, iHeight));
653 if (cIconFilePath != NULL)
654 {
655 cd_debug ("we replace X icon by %s", cIconFilePath);
656 cairo_surface_t *pSurface = cairo_dock_create_surface_from_image_simple (cIconFilePath,
657 iWidth,
658 iHeight);
659 g_free (cIconFilePath);
660 if (pSurface)
661 return pSurface;
662 }
663 }
664 }
665 }
666 }
667
668 // if we didn't find one, we use the icon defined in the class.
669 if (pClassAppli != NULL && pClassAppli->cIcon != NULL)
670 {
671 cd_debug ("get the class icon (%s)", pClassAppli->cIcon);
672 gchar *cIconFilePath = cairo_dock_search_icon_s_path (pClassAppli->cIcon, MAX (iWidth, iHeight));
673 cairo_surface_t *pSurface = cairo_dock_create_surface_from_image_simple (cIconFilePath,
674 iWidth,
675 iHeight);
676 g_free (cIconFilePath);
677 if (pSurface)
678 return pSurface;
679 }
680 else
681 {
682 cd_debug ("no icon for the class %s", cClass);
683 }
684
685 // if not found or not defined, try to find an icon based on the name class.
686 gchar *cIconFilePath = cairo_dock_search_icon_s_path (cClass, MAX (iWidth, iHeight));
687 if (cIconFilePath != NULL)
688 {
689 cd_debug ("we replace the X icon by %s", cIconFilePath);
690 cairo_surface_t *pSurface = cairo_dock_create_surface_from_image_simple (cIconFilePath,
691 iWidth,
692 iHeight);
693 g_free (cIconFilePath);
694 if (pSurface)
695 return pSurface;
696 }
697
698 cd_debug ("class %s will take the X icon", cClass);
699 return NULL;
700 }
701
702 /**
703 void cairo_dock_update_visibility_on_inhibitors (const gchar *cClass, GldiWindowActor *pAppli, gboolean bIsHidden)
704 {
705 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
706 if (pClassAppli != NULL)
707 {
708 GList *pElement;
709 Icon *pInhibitorIcon;
710 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
711 {
712 pInhibitorIcon = pElement->data;
713
714 if (pInhibitorIcon->pAppli == pAppli)
715 {
716 cd_debug (" %s also %s itself", pInhibitorIcon->cName, (bIsHidden ? "hide" : "show"));
717 if (! CAIRO_DOCK_ICON_TYPE_IS_APPLET (pInhibitorIcon) && myTaskbarParam.fVisibleAppliAlpha != 0)
718 {
719 pInhibitorIcon->fAlpha = 1; // we cheat a bit.
720 cairo_dock_redraw_icon (pInhibitorIcon);
721 }
722 }
723 }
724 }
725 }
726
727 void cairo_dock_update_activity_on_inhibitors (const gchar *cClass, GldiWindowActor *pAppli)
728 {
729 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
730 if (pClassAppli != NULL)
731 {
732 GList *pElement;
733 Icon *pInhibitorIcon;
734 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
735 {
736 pInhibitorIcon = pElement->data;
737
738 if (pInhibitorIcon->pAppli == pAppli)
739 {
740 cd_debug (" %s becomes active too", pInhibitorIcon->cName);
741 CairoDock *pParentDock = CAIRO_DOCK(cairo_dock_get_icon_container (pInhibitorIcon));
742 if (pParentDock != NULL)
743 gldi_appli_icon_animate_on_active (pInhibitorIcon, pParentDock);
744 }
745 }
746 }
747 }
748
749 void cairo_dock_update_inactivity_on_inhibitors (const gchar *cClass, GldiWindowActor *pAppli)
750 {
751 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
752 if (pClassAppli != NULL)
753 {
754 GList *pElement;
755 Icon *pInhibitorIcon;
756 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
757 {
758 pInhibitorIcon = pElement->data;
759
760 if (pInhibitorIcon->pAppli == pAppli)
761 {
762 cairo_dock_redraw_icon (pInhibitorIcon);
763 }
764 }
765 }
766 }
767
768 void cairo_dock_update_name_on_inhibitors (const gchar *cClass, GldiWindowActor *actor, gchar *cNewName)
769 {
770 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
771 if (pClassAppli != NULL)
772 {
773 GList *pElement;
774 Icon *pInhibitorIcon;
775 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
776 {
777 pInhibitorIcon = pElement->data;
778
779 if (pInhibitorIcon->pAppli == actor)
780 {
781 if (! CAIRO_DOCK_ICON_TYPE_IS_APPLET (pInhibitorIcon))
782 {
783 cd_debug (" %s change its name to %s", pInhibitorIcon->cName, cNewName);
784 if (pInhibitorIcon->cInitialName == NULL)
785 {
786 pInhibitorIcon->cInitialName = pInhibitorIcon->cName;
787 cd_debug ("pInhibitorIcon->cInitialName <- %s", pInhibitorIcon->cInitialName);
788 }
789 else
790 g_free (pInhibitorIcon->cName);
791 pInhibitorIcon->cName = NULL;
792
793 gldi_icon_set_name (pInhibitorIcon, (cNewName != NULL ? cNewName : pInhibitorIcon->cInitialName));
794 }
795 cairo_dock_redraw_icon (pInhibitorIcon);
796 }
797 }
798 }
799 }
800 */
gldi_window_foreach_inhibitor(GldiWindowActor * actor,GldiIconRFunc callback,gpointer data)801 void gldi_window_foreach_inhibitor (GldiWindowActor *actor, GldiIconRFunc callback, gpointer data)
802 {
803 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (actor->cClass);
804 if (pClassAppli != NULL)
805 {
806 Icon *pInhibitorIcon;
807 GList *ic;
808 for (ic = pClassAppli->pIconsOfClass; ic != NULL; ic = ic->next)
809 {
810 pInhibitorIcon = ic->data;
811 if (pInhibitorIcon->pAppli == actor)
812 {
813 if (! callback (pInhibitorIcon, data))
814 break;
815 }
816 }
817 }
818 }
819
820
cairo_dock_get_classmate(Icon * pIcon)821 Icon *cairo_dock_get_classmate (Icon *pIcon) // gets an icon of the same class, that is inside a dock (or will be for an inhibitor), but not inside the class sub-dock
822 {
823 cd_debug ("%s (%s)", __func__, pIcon->cClass);
824 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
825 if (pClassAppli == NULL)
826 return NULL;
827
828 Icon *pFriendIcon = NULL;
829 GList *pElement;
830 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
831 {
832 pFriendIcon = pElement->data;
833 /// TODO: this is ugly... maybe an inhibitor shouldn't inhibit when not yet in a dock...
834 if (pFriendIcon == NULL || (cairo_dock_get_icon_container(pFriendIcon) == NULL && pFriendIcon->cParentDockName == NULL)) // if not inside a dock (for instance a detached applet, but not a hidden launcher), ignore.
835 continue ;
836 cd_debug (" friend : %s", pFriendIcon->cName);
837 if (pFriendIcon->pAppli != NULL || pFriendIcon->pSubDock != NULL) // is linked to a window, 1 or several times (window actor or class sub-dock).
838 return pFriendIcon;
839 }
840
841 GldiContainer *pClassSubDock = CAIRO_CONTAINER(cairo_dock_get_class_subdock (pIcon->cClass));
842 for (pElement = pClassAppli->pAppliOfClass; pElement != NULL; pElement = pElement->next)
843 {
844 pFriendIcon = pElement->data;
845 if (pFriendIcon == pIcon) // skip ourselves
846 continue ;
847
848 if (cairo_dock_get_icon_container (pFriendIcon) != NULL && cairo_dock_get_icon_container (pFriendIcon) != pClassSubDock) // inside a dock, but not the class sub-dock
849 return pFriendIcon;
850 }
851
852 return NULL;
853 }
854
855
856
cairo_dock_check_class_subdock_is_empty(CairoDock * pDock,const gchar * cClass)857 gboolean cairo_dock_check_class_subdock_is_empty (CairoDock *pDock, const gchar *cClass)
858 {
859 cd_debug ("%s (%s, %d)", __func__, cClass, g_list_length (pDock->icons));
860 if (pDock->iRefCount == 0)
861 return FALSE;
862 if (pDock->icons == NULL) // shouldn't happen, handle this case and make some noise.
863 {
864 cd_warning ("the %s class sub-dock has no element, which is probably an error !\nit will be destroyed.", cClass);
865 Icon *pFakeClassIcon = cairo_dock_search_icon_pointing_on_dock (pDock, NULL);
866 cairo_dock_destroy_class_subdock (cClass);
867 pFakeClassIcon->pSubDock = NULL;
868 if (CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (pFakeClassIcon))
869 {
870 gldi_icon_detach (pFakeClassIcon);
871 gldi_object_unref (GLDI_OBJECT(pFakeClassIcon));
872 }
873 return TRUE;
874 }
875 else if (pDock->icons->next == NULL) // only 1 icon left in the sub-dock -> destroy it.
876 {
877 cd_debug (" the sub-dock of the class %s has now only one item in it: will be destroyed", cClass);
878 Icon *pLastClassIcon = pDock->icons->data;
879
880 CairoDock *pFakeParentDock = NULL;
881 Icon *pFakeClassIcon = cairo_dock_search_icon_pointing_on_dock (pDock, &pFakeParentDock);
882 g_return_val_if_fail (pFakeClassIcon != NULL, TRUE);
883
884 // detach the last icon from the class sub-dock
885 gboolean bLastIconIsRemoving = cairo_dock_icon_is_being_removed (pLastClassIcon); // keep the removing state because when we detach the icon, it returns to normal state.
886 gldi_icon_detach (pLastClassIcon);
887 pLastClassIcon->fOrder = pFakeClassIcon->fOrder; // if re-inserted in a dock, insert at the same place
888
889 // destroy the class sub-dock
890 cairo_dock_destroy_class_subdock (cClass);
891 pFakeClassIcon->pSubDock = NULL;
892
893 if (CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (pFakeClassIcon)) // the class sub-dock is pointed by a class-icon
894 {
895 // destroy the class-icon
896 gldi_icon_detach (pFakeClassIcon);
897 gldi_object_unref (GLDI_OBJECT(pFakeClassIcon));
898
899 // re-insert the last icon in place of it, or destroy it if it was being removed
900 if (! bLastIconIsRemoving)
901 {
902 gldi_icon_insert_in_container (pLastClassIcon, CAIRO_CONTAINER(pFakeParentDock), ! CAIRO_DOCK_ANIMATE_ICON);
903 }
904 else // the last icon is being removed, no need to re-insert it (e.g. when we close all classes in one it)
905 {
906 cd_debug ("no need to re-insert the last icon");
907 gldi_object_unref (GLDI_OBJECT(pLastClassIcon));
908 }
909 }
910 else // the class sub-dock is pointed by a launcher/applet
911 {
912 // re-inhibit the last icon or destroy it if it was being removed
913 if (! bLastIconIsRemoving)
914 {
915 gldi_appli_icon_insert_in_dock (pLastClassIcon, g_pMainDock, ! CAIRO_DOCK_ANIMATE_ICON); // Note that we could optimize and manually set the appli and the name...
916 ///cairo_dock_update_name_on_inhibitors (cClass, pLastClassIcon->pAppli, pLastClassIcon->cName);
917 }
918 else // the last icon is being removed, no need to re-insert it
919 {
920 pFakeClassIcon->bHasIndicator = FALSE;
921 gldi_object_unref (GLDI_OBJECT(pLastClassIcon));
922 }
923 cairo_dock_redraw_icon (pFakeClassIcon);
924 }
925 cd_debug ("no more dock");
926 return TRUE;
927 }
928 return FALSE;
929 }
930
931
_cairo_dock_reset_overwrite_exceptions(G_GNUC_UNUSED gchar * cClass,CairoDockClassAppli * pClassAppli,G_GNUC_UNUSED gpointer data)932 static void _cairo_dock_reset_overwrite_exceptions (G_GNUC_UNUSED gchar *cClass, CairoDockClassAppli *pClassAppli, G_GNUC_UNUSED gpointer data)
933 {
934 pClassAppli->bUseXIcon = FALSE;
935 }
cairo_dock_set_overwrite_exceptions(const gchar * cExceptions)936 void cairo_dock_set_overwrite_exceptions (const gchar *cExceptions)
937 {
938 g_hash_table_foreach (s_hClassTable, (GHFunc) _cairo_dock_reset_overwrite_exceptions, NULL);
939 if (cExceptions == NULL)
940 return;
941
942 gchar **cClassList = g_strsplit (cExceptions, ";", -1);
943 if (cClassList == NULL || cClassList[0] == NULL || *cClassList[0] == '\0')
944 {
945 g_strfreev (cClassList);
946 return;
947 }
948 CairoDockClassAppli *pClassAppli;
949 int i;
950 for (i = 0; cClassList[i] != NULL; i ++)
951 {
952 pClassAppli = cairo_dock_get_class (cClassList[i]);
953 pClassAppli->bUseXIcon = TRUE;
954 }
955
956 g_strfreev (cClassList);
957 }
958
_cairo_dock_reset_group_exceptions(G_GNUC_UNUSED gchar * cClass,CairoDockClassAppli * pClassAppli,G_GNUC_UNUSED gpointer data)959 static void _cairo_dock_reset_group_exceptions (G_GNUC_UNUSED gchar *cClass, CairoDockClassAppli *pClassAppli, G_GNUC_UNUSED gpointer data)
960 {
961 pClassAppli->bExpand = FALSE;
962 }
cairo_dock_set_group_exceptions(const gchar * cExceptions)963 void cairo_dock_set_group_exceptions (const gchar *cExceptions)
964 {
965 g_hash_table_foreach (s_hClassTable, (GHFunc) _cairo_dock_reset_group_exceptions, NULL);
966 if (cExceptions == NULL)
967 return;
968
969 gchar **cClassList = g_strsplit (cExceptions, ";", -1);
970 if (cClassList == NULL || cClassList[0] == NULL || *cClassList[0] == '\0')
971 {
972 g_strfreev (cClassList);
973 return;
974 }
975 CairoDockClassAppli *pClassAppli;
976 int i;
977 for (i = 0; cClassList[i] != NULL; i ++)
978 {
979 pClassAppli = cairo_dock_get_class (cClassList[i]);
980 pClassAppli->bExpand = TRUE;
981 }
982
983 g_strfreev (cClassList);
984 }
985
986
cairo_dock_get_prev_next_classmate_icon(Icon * pIcon,gboolean bNext)987 Icon *cairo_dock_get_prev_next_classmate_icon (Icon *pIcon, gboolean bNext)
988 {
989 cd_debug ("%s (%s, %s)", __func__, pIcon->cClass, pIcon->cName);
990 g_return_val_if_fail (pIcon->cClass != NULL, NULL);
991
992 Icon *pActiveIcon = cairo_dock_get_current_active_icon ();
993 if (pActiveIcon == NULL || pActiveIcon->cClass == NULL || strcmp (pActiveIcon->cClass, pIcon->cClass) != 0) // the active window is not from our class, we active the icon given in parameter.
994 {
995 cd_debug ("Active icon's class: %s", pIcon->cClass);
996 return pIcon;
997 }
998
999 //\________________ We are looking in the class of the active window and take the next or previous one.
1000 Icon *pNextIcon = NULL;
1001 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
1002 if (pClassAppli == NULL)
1003 return NULL;
1004
1005 //\________________ We are looking in icons of apps.
1006 Icon *pClassmateIcon;
1007 GList *pElement, *ic;
1008 for (pElement = pClassAppli->pAppliOfClass; pElement != NULL && pNextIcon == NULL; pElement = pElement->next)
1009 {
1010 pClassmateIcon = pElement->data;
1011 cd_debug (" %s is it active?", pClassmateIcon->cName);
1012 if (pClassmateIcon->pAppli == pActiveIcon->pAppli) // the active window.
1013 {
1014 cd_debug (" found an active window (%s; %p)", pClassmateIcon->cName, pClassmateIcon->pAppli);
1015 if (bNext) // take the 1st non null after that.
1016 {
1017 ic = pElement;
1018 do
1019 {
1020 ic = cairo_dock_get_next_element (ic, pClassAppli->pAppliOfClass);
1021 if (ic == pElement)
1022 {
1023 cd_debug (" found nothing!");
1024 break ;
1025 }
1026 pClassmateIcon = ic->data;
1027 if (pClassmateIcon != NULL && pClassmateIcon->pAppli != NULL)
1028 {
1029 cd_debug (" we take this one (%s; %p)", pClassmateIcon->cName, pClassmateIcon->pAppli);
1030 pNextIcon = pClassmateIcon;
1031 break ;
1032 }
1033 }
1034 while (1);
1035 }
1036 else // we take the first non null before it.
1037 {
1038 ic = pElement;
1039 do
1040 {
1041 ic = cairo_dock_get_previous_element (ic, pClassAppli->pAppliOfClass);
1042 if (ic == pElement)
1043 break ;
1044 pClassmateIcon = ic->data;
1045 if (pClassmateIcon != NULL && pClassmateIcon->pAppli != NULL)
1046 {
1047 pNextIcon = pClassmateIcon;
1048 break ;
1049 }
1050 }
1051 while (1);
1052 }
1053 break ;
1054 }
1055 }
1056 return pNextIcon;
1057 }
1058
1059
1060
cairo_dock_get_inhibitor(Icon * pIcon,gboolean bOnlyInDock)1061 Icon *cairo_dock_get_inhibitor (Icon *pIcon, gboolean bOnlyInDock)
1062 {
1063 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
1064 if (pClassAppli != NULL)
1065 {
1066 GList *pElement;
1067 Icon *pInhibitorIcon;
1068 for (pElement = pClassAppli->pIconsOfClass; pElement != NULL; pElement = pElement->next)
1069 {
1070 pInhibitorIcon = pElement->data;
1071
1072 if (pInhibitorIcon->pAppli == pIcon->pAppli)
1073 {
1074 if (! bOnlyInDock || cairo_dock_get_icon_container (pInhibitorIcon) != NULL)
1075 return pInhibitorIcon;
1076 }
1077 }
1078 }
1079 return NULL;
1080 }
1081
1082 /* Not used
1083 static gboolean _appli_is_older (Icon *pIcon1, Icon *pIcon2, CairoDockClassAppli *pClassAppli) // TRUE if icon1 older than icon2
1084 {
1085 Icon *pAppliIcon;
1086 GList *ic;
1087 for (ic = pClassAppli->pAppliOfClass; ic != NULL; ic = ic->next)
1088 {
1089 pAppliIcon = ic->data;
1090 if (pAppliIcon == pIcon1) // we found the icon1 first, so icon1 is more recent (prepend).
1091 return FALSE;
1092 if (pAppliIcon == pIcon2) // we found the icon2 first, so icon2 is more recent (prepend).
1093 return TRUE;
1094 }
1095 return FALSE;
1096 }
1097 */
_get_previous_order(GList * ic)1098 static inline double _get_previous_order (GList *ic)
1099 {
1100 if (ic == NULL)
1101 return 0;
1102 double fOrder;
1103 Icon *icon = ic->data;
1104 Icon *prev_icon = (ic->prev ? ic->prev->data : NULL);
1105 if (prev_icon != NULL && cairo_dock_get_icon_order (prev_icon) == cairo_dock_get_icon_order (icon))
1106
1107 fOrder = (icon->fOrder + prev_icon->fOrder) / 2;
1108 else
1109 fOrder = icon->fOrder - 1;
1110 return fOrder;
1111 }
_get_next_order(GList * ic)1112 static inline double _get_next_order (GList *ic)
1113 {
1114 if (ic == NULL)
1115 return 0;
1116 double fOrder;
1117 Icon *icon = ic->data;
1118 Icon *next_icon = (ic->next ? ic->next->data : NULL);
1119 if (next_icon != NULL && cairo_dock_get_icon_order (next_icon) == cairo_dock_get_icon_order (icon))
1120 fOrder = (icon->fOrder + next_icon->fOrder) / 2;
1121 else
1122 fOrder = icon->fOrder + 1;
1123 return fOrder;
1124 }
_get_first_appli_order(CairoDock * pDock,GList * first_launcher_ic,GList * last_launcher_ic)1125 static inline double _get_first_appli_order (CairoDock *pDock, GList *first_launcher_ic, GList *last_launcher_ic)
1126 {
1127 double fOrder;
1128 switch (myTaskbarParam.iIconPlacement)
1129 {
1130 case CAIRO_APPLI_BEFORE_FIRST_ICON:
1131 fOrder = _get_previous_order (pDock->icons);
1132 break;
1133
1134 case CAIRO_APPLI_BEFORE_FIRST_LAUNCHER:
1135 if (first_launcher_ic != NULL)
1136 {
1137 //g_print (" go just before the first launcher (%s)\n", ((Icon*)first_launcher_ic->data)->cName);
1138 fOrder = _get_previous_order (first_launcher_ic); // 'first_launcher_ic' includes the separators, so we can just take the previous order.
1139 }
1140 else // no launcher, go to the beginning of the dock.
1141 {
1142 fOrder = _get_previous_order (pDock->icons);
1143 }
1144 break;
1145
1146 case CAIRO_APPLI_AFTER_ICON:
1147 {
1148 Icon *icon;
1149 GList *ic = NULL;
1150 for (ic = pDock->icons; ic != NULL; ic = ic->next)
1151 {
1152 icon = ic->data;
1153 if ((icon->cDesktopFileName != NULL && g_strcmp0 (icon->cDesktopFileName, myTaskbarParam.cRelativeIconName) == 0)
1154 || (icon->pModuleInstance && g_strcmp0 (icon->pModuleInstance->cConfFilePath, myTaskbarParam.cRelativeIconName) == 0))
1155 break;
1156 }
1157
1158 if (ic != NULL) // icon found
1159 {
1160 fOrder = _get_next_order (ic);
1161 break;
1162 } // else don't break, and go to the 'CAIRO_APPLI_AFTER_LAST_LAUNCHER' case, which will be the fallback.
1163 }
1164
1165 case CAIRO_APPLI_AFTER_LAST_LAUNCHER:
1166 default:
1167 if (last_launcher_ic != NULL)
1168 {
1169 //g_print (" go just after the last launcher (%s)\n", ((Icon*)last_launcher_ic->data)->cName);
1170 fOrder = _get_next_order (last_launcher_ic);
1171 }
1172 else // no launcher, go to the beginning of the dock.
1173 {
1174 fOrder = _get_previous_order (pDock->icons);
1175 }
1176 break;
1177
1178 case CAIRO_APPLI_AFTER_LAST_ICON:
1179 fOrder = _get_next_order (g_list_last (pDock->icons));
1180 break;
1181 }
1182 return fOrder;
1183 }
_get_class_age(CairoDockClassAppli * pClassAppli)1184 static inline int _get_class_age (CairoDockClassAppli *pClassAppli)
1185 {
1186 if (pClassAppli->pAppliOfClass == NULL)
1187 return 0;
1188 return pClassAppli->iAge;
1189 }
1190 // Set the order of an appli when they are mixed amongst launchers and no class sub-dock exists (because either they are not grouped by class, or just it's the first appli of this class in the dock)
1191 // First try to see if an inhibitor is present in the dock; if not, see if an appli of the same class is present in the dock.
1192 // -> if yes, place it next to it, ordered by age (go to the right until our age is greater)
1193 // -> if no, place it amongst the other appli icons, ordered by age (search the last launcher, skip any automatic separator, and then go to the right until our age is greater or there is no more appli).
cairo_dock_set_class_order_in_dock(Icon * pIcon,CairoDock * pDock)1194 void cairo_dock_set_class_order_in_dock (Icon *pIcon, CairoDock *pDock)
1195 {
1196 //g_print ("%s (%s, %d)\n", __func__, pIcon->cClass, pIcon->iAge);
1197 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
1198 g_return_if_fail (pClassAppli != NULL);
1199
1200 // Look for an icon of the same class in the dock, to place ourself relatively to it.
1201 Icon *pSameClassIcon = NULL;
1202 GList *same_class_ic = NULL;
1203
1204 // First look for an inhibitor of this class, preferably a launcher.
1205 CairoDock *pParentDock;
1206 Icon *pInhibitorIcon;
1207 GList *ic;
1208 for (ic = pClassAppli->pIconsOfClass; ic != NULL; ic = ic->next)
1209 {
1210 pInhibitorIcon = ic->data;
1211
1212 pParentDock = CAIRO_DOCK(cairo_dock_get_icon_container (pInhibitorIcon));
1213 if (! GLDI_OBJECT_IS_DOCK(pParentDock)) // not inside a dock, for instance a desklet (or a hidden launcher) -> skip
1214 continue;
1215 pSameClassIcon = pInhibitorIcon;
1216 same_class_ic = ic;
1217 //g_print (" found an inhibitor of this class: %s (%d)\n", pSameClassIcon->cName, pSameClassIcon->iAge);
1218 if (CAIRO_DOCK_ICON_TYPE_IS_LAUNCHER (pSameClassIcon)) // it's a launcher, we wont't find better -> quit
1219 break ;
1220 }
1221
1222 // if no inhibitor found, look for an appli of this class in the dock.
1223 if (pSameClassIcon == NULL)
1224 {
1225 Icon *pAppliIcon;
1226 for (ic = g_list_last (pClassAppli->pAppliOfClass); ic != NULL; ic = ic->prev) // check the older icons first (prepend), because then we'll place ourself to their right.
1227 {
1228 pAppliIcon = ic->data;
1229 if (pAppliIcon == pIcon) // skip ourself
1230 continue;
1231 pParentDock = CAIRO_DOCK(cairo_dock_get_icon_container (pAppliIcon));
1232 if (pParentDock != NULL)
1233 {
1234 pSameClassIcon = pAppliIcon;
1235 same_class_ic = ic;
1236 //g_print (" found an appli of this class: %s (%d)\n", pSameClassIcon->cName, pSameClassIcon->iAge);
1237 break ;
1238 }
1239 }
1240 pIcon->iGroup = (myTaskbarParam.bSeparateApplis ? CAIRO_DOCK_APPLI : CAIRO_DOCK_LAUNCHER); // no inhibitor, so we'll go in the taskbar group.
1241 }
1242 else // an inhibitor is present, we'll go next to it, so we'll be in its group.
1243 {
1244 pIcon->iGroup = pSameClassIcon->iGroup;
1245 }
1246
1247 // if we found one, place next to it, ordered by age amongst the other appli of this class already in the dock.
1248 if (pSameClassIcon != NULL)
1249 {
1250 same_class_ic = g_list_find (pDock->icons, pSameClassIcon);
1251 g_return_if_fail (same_class_ic != NULL);
1252 Icon *pNextIcon = NULL; // the next icon after all the icons of our class, or NULL if we reach the end of the dock.
1253 for (ic = same_class_ic->next; ic != NULL; ic = ic->next)
1254 {
1255 pNextIcon = ic->data;
1256 //g_print (" next icon: %s (%d)\n", pNextIcon->cName, pNextIcon->iAge);
1257 if (!pNextIcon->cClass || strcmp (pNextIcon->cClass, pIcon->cClass) != 0) // not our class any more, quit.
1258 break;
1259
1260 if (pIcon->pAppli->iAge > pNextIcon->pAppli->iAge) // we are more recent than this icon -> place on its right -> continue
1261 {
1262 pSameClassIcon = pNextIcon; // 'pSameClassIcon' will be the last icon of our class older than us.
1263 pNextIcon = NULL;
1264 }
1265 else // we are older than it -> go just before it -> quit
1266 {
1267 break;
1268 }
1269 }
1270 //g_print (" pNextIcon: %s (%d)\n", pNextIcon?pNextIcon->cName:"none", pNextIcon?pNextIcon->iAge:-1);
1271
1272 if (pNextIcon != NULL && cairo_dock_get_icon_order (pNextIcon) == cairo_dock_get_icon_order (pSameClassIcon)) // the next icon is in thge09e same group as us: place it between this icon and pSameClassIcon.
1273 pIcon->fOrder = (pNextIcon->fOrder + pSameClassIcon->fOrder) / 2;
1274 else // no icon after our class or in a different grou: we place just after pSameClassIcon.
1275 pIcon->fOrder = pSameClassIcon->fOrder + 1;
1276
1277 return;
1278 }
1279
1280 // if no icon of our class is present in the dock, place it amongst the other appli icons, after the first appli or after the launchers, and ordered by age.
1281 // search the last launcher and the first appli.
1282 Icon *icon;
1283 Icon *pFirstLauncher = NULL;
1284 GList *first_appli_ic = NULL, *last_launcher_ic = NULL, *first_launcher_ic = NULL;
1285 for (ic = pDock->icons; ic != NULL; ic = ic->next)
1286 {
1287 icon = ic->data;
1288 if (CAIRO_DOCK_ICON_TYPE_IS_LAUNCHER (icon) // launcher, even without class
1289 || CAIRO_DOCK_ICON_TYPE_IS_CONTAINER (icon) // container icon (likely to contain some launchers)
1290 || (CAIRO_DOCK_ICON_TYPE_IS_APPLET (icon) && icon->pModuleInstance->pModule->pVisitCard->bActAsLauncher) // applet acting like a launcher
1291 /**|| CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon)*/) // separator (user or auto).
1292 {
1293 // pLastLauncher = icon;
1294 last_launcher_ic = ic;
1295 if (pFirstLauncher == NULL)
1296 {
1297 pFirstLauncher = icon;
1298 first_launcher_ic = ic;
1299 }
1300 }
1301 else if ((CAIRO_DOCK_ICON_TYPE_IS_APPLI (icon) || CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (icon))
1302 && ! cairo_dock_class_is_inhibited (icon->cClass)) // an appli not placed next to its inhibitor.
1303 {
1304 // pFirstAppli = icon;
1305 first_appli_ic = ic;
1306 break ;
1307 }
1308 }
1309 //g_print (" last launcher: %s\n", pLastLauncher?pLastLauncher->cName:"none");
1310 //g_print (" first appli: %s\n", pFirstAppli?pFirstAppli->cName:"none");
1311
1312 // place amongst the other applis, or after the last launcher.
1313 if (first_appli_ic != NULL) // if an appli exists in the dock, use it as an anchor.
1314 {
1315 int iAge = _get_class_age (pClassAppli); // the age of our class.
1316
1317 GList *last_appli_ic = NULL; // last appli whose class is older than ours => we'll go just after.
1318 for (ic = first_appli_ic; ic != NULL; ic = ic->next)
1319 {
1320 icon = ic->data;
1321 if (! CAIRO_DOCK_ICON_TYPE_IS_APPLI (icon) && ! CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (icon))
1322 break;
1323
1324 // get the age of this class (= age of the oldest icon of this class)
1325 CairoDockClassAppli *pOtherClassAppli = _cairo_dock_lookup_class_appli (icon->cClass);
1326 if (! pOtherClassAppli || ! pOtherClassAppli->pAppliOfClass) // should never happen
1327 continue;
1328
1329 int iOtherClassAge = _get_class_age (pOtherClassAppli);
1330 //g_print (" age of class %s: %d\n", icon->cClass, iOtherClassAge);
1331
1332 // compare to our class.
1333 if (iOtherClassAge < iAge) // it's older than our class -> skip this whole class, we'll go after.
1334 {
1335 Icon *next_icon;
1336 while (ic->next != NULL)
1337 {
1338 next_icon = ic->next->data;
1339 if (next_icon->cClass && strcmp (next_icon->cClass, icon->cClass) == 0) // next icon is of the same class -> skip
1340 ic = ic->next;
1341 else
1342 break;
1343 }
1344 last_appli_ic = ic;
1345 }
1346 else // we are older -> discard and quit.
1347 {
1348 break;
1349 }
1350 }
1351
1352 if (last_appli_ic == NULL) // we are the oldest class -> go just before the first appli
1353 {
1354 //g_print (" we are the oldest class\n");
1355 pIcon->fOrder = _get_previous_order (first_appli_ic);
1356 }
1357 else // go just after the last one
1358 {
1359 //g_print (" go just after %s\n", ((Icon*)last_appli_ic->data)->cName);
1360 pIcon->fOrder = _get_next_order (last_appli_ic);
1361 }
1362 }
1363 else // no appli yet in the dock -> place it at the taskbar position defined in conf.
1364 {
1365 pIcon->fOrder = _get_first_appli_order (pDock, first_launcher_ic, last_launcher_ic);
1366 }
1367 }
1368
cairo_dock_set_class_order_amongst_applis(Icon * pIcon,CairoDock * pDock)1369 void cairo_dock_set_class_order_amongst_applis (Icon *pIcon, CairoDock *pDock) // set the order of an appli amongst the other applis of a given dock (class sub-dock or main dock).
1370 {
1371 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (pIcon->cClass);
1372 g_return_if_fail (pClassAppli != NULL);
1373
1374 // place the icon amongst the other appli icons of this class, or after the last appli if none.
1375 if (myTaskbarParam.bSeparateApplis)
1376 pIcon->iGroup = CAIRO_DOCK_APPLI;
1377 else
1378 pIcon->iGroup = CAIRO_DOCK_LAUNCHER;
1379 Icon *icon;
1380 GList *ic, *last_ic = NULL, *first_appli_ic = NULL;
1381 GList *last_launcher_ic = NULL, *first_launcher_ic = NULL;
1382 for (ic = pDock->icons; ic != NULL; ic = ic->next)
1383 {
1384 icon = ic->data;
1385 if (CAIRO_DOCK_ICON_TYPE_IS_APPLI (icon))
1386 {
1387 if (! first_appli_ic)
1388 first_appli_ic = ic;
1389 if (icon->cClass && strcmp (icon->cClass, pIcon->cClass) == 0) // this icon is in our class.
1390 {
1391 if (!icon->pAppli || icon->pAppli->iAge < pIcon->pAppli->iAge) // it's older than us => we are more recent => go after => continue. (Note: icon->pAppli can be NULL if the icon in the dock is being removed)
1392 {
1393 last_ic = ic; // remember the last item of our class.
1394 }
1395 else // we are older than it => go just before it.
1396 {
1397 pIcon->fOrder = _get_previous_order (ic);
1398 return ;
1399 }
1400 }
1401 }
1402 else if (CAIRO_DOCK_ICON_TYPE_IS_LAUNCHER (icon) // launcher, even without class
1403 || CAIRO_DOCK_ICON_TYPE_IS_CONTAINER (icon) // container icon (likely to contain some launchers)
1404 || (CAIRO_DOCK_ICON_TYPE_IS_APPLET (icon) && icon->cClass != NULL && icon->pModuleInstance->pModule->pVisitCard->bActAsLauncher) // applet acting like a launcher
1405 || (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))) // separator (user or auto).
1406 {
1407 last_launcher_ic = ic;
1408 if (first_launcher_ic == NULL)
1409 {
1410 first_launcher_ic = ic;
1411 }
1412 }
1413 }
1414
1415 if (last_ic != NULL) // there are some applis of our class, but none are more recent than us, so we are the most recent => go just after the last one we found previously.
1416 {
1417 pIcon->fOrder = _get_next_order (last_ic);
1418 }
1419 else // we didn't find a single icon of our class => place amongst the other applis from age.
1420 {
1421 if (first_appli_ic != NULL) // if an appli exists in the dock, use it as an anchor.
1422 {
1423 Icon *pOldestAppli = g_list_last (pClassAppli->pAppliOfClass)->data; // prepend
1424 int iAge = pOldestAppli->pAppli->iAge; // the age of our class.
1425
1426 GList *last_appli_ic = NULL; // last appli whose class is older than ours => we'll go just after.
1427 for (ic = first_appli_ic; ic != NULL; ic = ic->next)
1428 {
1429 icon = ic->data;
1430 if (! CAIRO_DOCK_ICON_TYPE_IS_APPLI (icon) && ! CAIRO_DOCK_IS_MULTI_APPLI (icon))
1431 break;
1432
1433 // get the age of this class (= age of the oldest icon of this class)
1434 CairoDockClassAppli *pOtherClassAppli = _cairo_dock_lookup_class_appli (icon->cClass);
1435 if (! pOtherClassAppli || ! pOtherClassAppli->pAppliOfClass) // should never happen
1436 continue;
1437
1438 Icon *pOldestAppli = g_list_last (pOtherClassAppli->pAppliOfClass)->data; // prepend
1439
1440 // compare to our class.
1441 if (pOldestAppli->pAppli->iAge < iAge) // it's older than our class -> skip this whole class, we'll go after.
1442 {
1443 while (ic->next != NULL)
1444 {
1445 icon = ic->next->data;
1446 if (CAIRO_DOCK_ICON_TYPE_IS_APPLI (icon) && icon->cClass && strcmp (icon->cClass, pOldestAppli->cClass) == 0) // next icon is an appli of the same class -> skip
1447 ic = ic->next;
1448 else
1449 break;
1450 }
1451 last_appli_ic = ic;
1452 }
1453 else // we are older -> discard and quit.
1454 {
1455 break;
1456 }
1457 }
1458
1459 if (last_appli_ic == NULL) // we are the oldest class -> go just before the first appli
1460 {
1461 pIcon->fOrder = _get_previous_order (first_appli_ic);
1462 }
1463 else // go just after the last one
1464 {
1465 pIcon->fOrder = _get_next_order (last_appli_ic);
1466 }
1467 }
1468 else // no appli, use the defined placement.
1469 {
1470 pIcon->fOrder = _get_first_appli_order (pDock, first_launcher_ic, last_launcher_ic);
1471 }
1472 }
1473 }
1474
1475
_get_class_appli_with_attributes(const gchar * cClass)1476 static inline CairoDockClassAppli *_get_class_appli_with_attributes (const gchar *cClass)
1477 {
1478 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
1479 if (! pClassAppli->bSearchedAttributes)
1480 {
1481 gchar *cClass2 = cairo_dock_register_class (cClass);
1482 g_free (cClass2);
1483 }
1484 return pClassAppli;
1485 }
cairo_dock_get_class_command(const gchar * cClass)1486 const gchar *cairo_dock_get_class_command (const gchar *cClass)
1487 {
1488 g_return_val_if_fail (cClass != NULL, NULL);
1489 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1490 return pClassAppli->cCommand;
1491 }
1492
cairo_dock_get_class_name(const gchar * cClass)1493 const gchar *cairo_dock_get_class_name (const gchar *cClass)
1494 {
1495 g_return_val_if_fail (cClass != NULL, NULL);
1496 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1497 return pClassAppli->cName;
1498 }
1499
cairo_dock_get_class_mimetypes(const gchar * cClass)1500 const gchar **cairo_dock_get_class_mimetypes (const gchar *cClass)
1501 {
1502 g_return_val_if_fail (cClass != NULL, NULL);
1503 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1504 return (const gchar **)pClassAppli->pMimeTypes;
1505 }
1506
cairo_dock_get_class_desktop_file(const gchar * cClass)1507 const gchar *cairo_dock_get_class_desktop_file (const gchar *cClass)
1508 {
1509 g_return_val_if_fail (cClass != NULL, NULL);
1510 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1511 return pClassAppli->cDesktopFile;
1512 }
1513
cairo_dock_get_class_icon(const gchar * cClass)1514 const gchar *cairo_dock_get_class_icon (const gchar *cClass)
1515 {
1516 g_return_val_if_fail (cClass != NULL, NULL);
1517 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1518 return pClassAppli->cIcon;
1519 }
1520
cairo_dock_get_class_menu_items(const gchar * cClass)1521 const GList *cairo_dock_get_class_menu_items (const gchar *cClass)
1522 {
1523 g_return_val_if_fail (cClass != NULL, NULL);
1524 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1525 return pClassAppli->pMenuItems;
1526 }
1527
cairo_dock_get_class_wm_class(const gchar * cClass)1528 const gchar *cairo_dock_get_class_wm_class (const gchar *cClass)
1529 {
1530 g_return_val_if_fail (cClass != NULL, NULL);
1531 CairoDockClassAppli *pClassAppli = _get_class_appli_with_attributes (cClass);
1532
1533 if (pClassAppli->cStartupWMClass == NULL) // if the WMClass has not been retrieved beforehand, do it now
1534 {
1535 cd_debug ("retrieve WMClass for %s...", cClass);
1536 Icon *pIcon;
1537 GList *ic;
1538 for (ic = pClassAppli->pAppliOfClass; ic != NULL; ic = ic->next)
1539 {
1540 pIcon = ic->data;
1541 if (pIcon->pAppli && pIcon->pAppli->cWmClass)
1542 {
1543 pClassAppli->cStartupWMClass = g_strdup (pIcon->pAppli->cWmClass);
1544 break;
1545 }
1546 }
1547 }
1548
1549 return pClassAppli->cStartupWMClass;
1550 }
1551
cairo_dock_get_class_image_buffer(const gchar * cClass)1552 const CairoDockImageBuffer *cairo_dock_get_class_image_buffer (const gchar *cClass)
1553 {
1554 static CairoDockImageBuffer image;
1555 g_return_val_if_fail (cClass != NULL, NULL);
1556 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
1557 Icon *pIcon;
1558 GList *ic;
1559 for (ic = pClassAppli->pIconsOfClass; ic != NULL; ic = ic->next)
1560 {
1561 pIcon = ic->data;
1562 if (CAIRO_DOCK_ICON_TYPE_IS_LAUNCHER (pIcon) && pIcon->image.pSurface) // avoid applets
1563 {
1564 memcpy (&image, &pIcon->image, sizeof (CairoDockImageBuffer));
1565 return ℑ
1566 }
1567 }
1568 for (ic = pClassAppli->pAppliOfClass; ic != NULL; ic = ic->next)
1569 {
1570 pIcon = ic->data;
1571 if (pIcon->image.pSurface)
1572 {
1573 memcpy (&image, &pIcon->image, sizeof (CairoDockImageBuffer));
1574 return ℑ
1575 }
1576 }
1577
1578 return NULL;
1579 }
1580
1581
_search_desktop_file(const gchar * cDesktopFile)1582 static gchar *_search_desktop_file (const gchar *cDesktopFile) // file, path or even class
1583 {
1584 if (cDesktopFile == NULL)
1585 return NULL;
1586 if (*cDesktopFile == '/' && g_file_test (cDesktopFile, G_FILE_TEST_EXISTS)) // it's a path and it exists.
1587 {
1588 return g_strdup (cDesktopFile);
1589 }
1590
1591 gchar *cDesktopFileName = NULL;
1592 if (*cDesktopFile == '/')
1593 cDesktopFileName = g_path_get_basename (cDesktopFile);
1594 else if (! g_str_has_suffix (cDesktopFile, ".desktop"))
1595 cDesktopFileName = g_strdup_printf ("%s.desktop", cDesktopFile);
1596
1597 const gchar *cFileName = (cDesktopFileName ? cDesktopFileName : cDesktopFile);
1598 gboolean bFound = TRUE;
1599 GString *sDesktopFilePath = g_string_new ("");
1600 g_string_printf (sDesktopFilePath, "/usr/local/share/applications/%s", cFileName);
1601 if (! g_file_test (sDesktopFilePath->str, G_FILE_TEST_EXISTS))
1602 {
1603 g_string_printf (sDesktopFilePath, "/usr/local/share/applications/%c%s", g_ascii_toupper (*cFileName), cFileName+1); // handle stupid cases like Thunar.desktop
1604 if (! g_file_test (sDesktopFilePath->str, G_FILE_TEST_EXISTS))
1605 {
1606 g_string_printf (sDesktopFilePath, "/usr/local/share/applications/xfce4/%s", cFileName);
1607 if (! g_file_test (sDesktopFilePath->str, G_FILE_TEST_EXISTS))
1608 {
1609 g_string_printf (sDesktopFilePath, "/usr/local/share/applications/kde4/%s", cFileName);
1610 if (! g_file_test (sDesktopFilePath->str, G_FILE_TEST_EXISTS))
1611 {
1612 g_string_printf (sDesktopFilePath, "%s/.local/share/applications/%s", g_getenv ("HOME"), cFileName);
1613 if (! g_file_test (sDesktopFilePath->str, G_FILE_TEST_EXISTS))
1614 {
1615 bFound = FALSE;
1616 }
1617 }
1618 }
1619 }
1620 }
1621 g_free (cDesktopFileName);
1622
1623 gchar *cResult;
1624 if (bFound)
1625 {
1626 cResult = sDesktopFilePath->str;
1627 g_string_free (sDesktopFilePath, FALSE);
1628 }
1629 else
1630 {
1631 cResult = NULL;
1632 g_string_free (sDesktopFilePath, TRUE);
1633 }
1634 return cResult;
1635 }
1636
cairo_dock_guess_class(const gchar * cCommand,const gchar * cStartupWMClass)1637 gchar *cairo_dock_guess_class (const gchar *cCommand, const gchar *cStartupWMClass)
1638 {
1639 // Several cases are possible:
1640 // Exec=toto
1641 // Exec=toto-1.2
1642 // Exec=toto -x -y
1643 // Exec=/path/to/toto -x -y
1644 // Exec=gksu nautilus / (or kdesu)
1645 // Exec=su-to-root -X -c /usr/sbin/synaptic
1646 // Exec=gksu --description /usr/local/share/applications/synaptic.desktop /usr/sbin/synaptic
1647 // Exec=wine "C:\Program Files\Starcraft\Starcraft.exe"
1648 // Exec=wine "/path/to/prog.exe"
1649 // Exec=env WINEPREFIX="/home/fab/.wine" wine "C:\Program Files\Starcraft\Starcraft.exe"
1650
1651 cd_debug ("%s (%s, '%s')", __func__, cCommand, cStartupWMClass);
1652 gchar *cResult = NULL;
1653 if (cStartupWMClass == NULL || *cStartupWMClass == '\0' || strcmp (cStartupWMClass, "Wine") == 0) // special case for wine, because even if the class is defined as "Wine", this information is non-exploitable.
1654 {
1655 if (cCommand == NULL || *cCommand == '\0')
1656 return NULL;
1657 gchar *cDefaultClass = g_ascii_strdown (cCommand, -1);
1658 gchar *str;
1659 const gchar *cClass = cDefaultClass; // pointer to the current class.
1660
1661 if (strncmp (cClass, "gksu", 4) == 0 || strncmp (cClass, "kdesu", 5) == 0 || strncmp (cClass, "su-to-root", 10) == 0) // we take the end
1662 {
1663 str = (gchar*)cClass + strlen(cClass) - 1; // last char.
1664 while (*str == ' ') // by security, we remove spaces at the end of the line.
1665 *(str--) = '\0';
1666 str = strchr (cClass, ' '); // first whitespace.
1667 if (str != NULL) // we are looking after that.
1668 {
1669 while (*str == ' ')
1670 str ++;
1671 cClass = str;
1672 } // we remove gksu, kdesu, etc..
1673 if (*cClass == '-') // if it's an option: we need the last param.
1674 {
1675 str = strrchr (cClass, ' '); // last whitespace.
1676 if (str != NULL) // we are looking after that.
1677 cClass = str + 1;
1678 }
1679 else // we can use the first param
1680 {
1681 str = strchr (cClass, ' '); // first whitespace.
1682 if (str != NULL) // we remove everything after that
1683 *str = '\0';
1684 }
1685
1686 str = strrchr (cClass, '/'); // last '/'.
1687 if (str != NULL) // remove after that.
1688 cClass = str + 1;
1689 }
1690 else if ((str = g_strstr_len (cClass, -1, "wine ")) != NULL)
1691 {
1692 cClass = str; // class = wine, better than nothing.
1693 *(str+4) = '\0';
1694 str += 5;
1695 while (*str == ' ') // we remove extra whitespaces.
1696 str ++;
1697 // we try to find the executable which is used by wine as res_name.
1698 gchar *exe = g_strstr_len (str, -1, ".exe");
1699 if (!exe)
1700 exe = g_strstr_len (str, -1, ".EXE");
1701 if (exe)
1702 {
1703 *exe = '\0'; // remove the extension.
1704 gchar *slash = strrchr (str, '\\');
1705 if (slash)
1706 cClass = slash+1;
1707 else
1708 {
1709 slash = strrchr (str, '/');
1710 if (slash)
1711 cClass = slash+1;
1712 else
1713 cClass = str;
1714 }
1715 }
1716 cd_debug (" special case : wine application => class = '%s'", cClass);
1717 }
1718 else
1719 {
1720 while (*cClass == ' ') // by security, remove extra whitespaces.
1721 cClass ++;
1722 str = strchr (cClass, ' '); // first whitespace.
1723 if (str != NULL) // remove everything after that
1724 *str = '\0';
1725 str = strrchr (cClass, '/'); // last '/'.
1726 if (str != NULL) // we take after that.
1727 cClass = str + 1;
1728 str = strchr (cClass, '.'); // we remove all .xxx otherwise we can't detect the lack of extension when looking for an icon (openoffice.org) or it's a problem when looking for an icon (jbrout.py).
1729 if (str != NULL && str != cClass)
1730 *str = '\0';
1731 }
1732
1733 // handle the cases of programs where command != class.
1734 if (*cClass != '\0')
1735 {
1736 if (strncmp (cClass, "oo", 2) == 0)
1737 {
1738 if (strcmp (cClass, "ooffice") == 0 || strcmp (cClass, "oowriter") == 0 || strcmp (cClass, "oocalc") == 0 || strcmp (cClass, "oodraw") == 0 || strcmp (cClass, "ooimpress") == 0) // openoffice poor design: there is no way to bind its windows to the launcher without this trick.
1739 cClass = "openoffice";
1740 }
1741 else if (strncmp (cClass, "libreoffice", 11) == 0) // libreoffice has different classes according to the launching option (--writer => libreoffice-writer, --calc => libreoffice-calc, etc)
1742 {
1743 gchar *str = strchr (cCommand, ' ');
1744 if (str && *(str+1) == '-')
1745 {
1746 g_free (cDefaultClass);
1747 cDefaultClass = g_strdup_printf ("%s%s", "libreoffice", str+2);
1748 str = strchr (cDefaultClass, ' '); // remove the additionnal params of the command.
1749 if (str)
1750 *str = '\0';
1751 cClass = cDefaultClass; // "libreoffice-writer"
1752 }
1753 }
1754 cResult = g_strdup (cClass);
1755 }
1756 g_free (cDefaultClass);
1757 }
1758 else
1759 {
1760 cResult = g_ascii_strdown (cStartupWMClass, -1);
1761 gchar *str = strchr (cResult, '.'); // we remove all .xxx otherwise we can't detect the lack of extension when looking for an icon (openoffice.org) or it's a problem when looking for an icon (jbrout.py).
1762 if (str != NULL)
1763 *str = '\0';
1764 }
1765 cairo_dock_remove_version_from_string (cResult);
1766 cd_debug (" -> '%s'", cResult);
1767
1768 return cResult;
1769 }
1770
_add_action_menus(GKeyFile * pKeyFile,CairoDockClassAppli * pClassAppli,const gchar * cGettextDomain,const gchar * cMenuListKey,const gchar * cMenuGroup,gboolean bActionFirstInGroupKey)1771 static void _add_action_menus (GKeyFile *pKeyFile, CairoDockClassAppli *pClassAppli, const gchar *cGettextDomain, const gchar *cMenuListKey, const gchar *cMenuGroup, gboolean bActionFirstInGroupKey)
1772 {
1773 gsize length = 0;
1774 gchar **pMenuList = g_key_file_get_string_list (pKeyFile, "Desktop Entry", cMenuListKey, &length, NULL);
1775 if (pMenuList != NULL)
1776 {
1777 gchar *cGroup;
1778 int i;
1779 for (i = 0; pMenuList[i] != NULL; i++)
1780 {
1781 cGroup = g_strdup_printf ("%s %s",
1782 bActionFirstInGroupKey ? pMenuList[i] : cMenuGroup, // [NewWindow Shortcut Group]
1783 bActionFirstInGroupKey ? cMenuGroup : pMenuList [i]); // [Desktop Action NewWindow]
1784
1785 if (g_key_file_has_group (pKeyFile, cGroup))
1786 {
1787 gchar **pMenuItem = g_new0 (gchar*, 4);
1788 // for a few apps, the translations are directly available in the .desktop file (e.g. firefox)
1789 gchar *cName = g_key_file_get_locale_string (pKeyFile, cGroup, "Name", NULL, NULL);
1790 pMenuItem[0] = g_strdup (dgettext (cGettextDomain, cName)); // but most of the time, it's available in the .mo file
1791 g_free (cName);
1792 gchar *cCommand = g_key_file_get_string (pKeyFile, cGroup, "Exec", NULL);
1793 if (cCommand != NULL) // remove the launching options %x.
1794 {
1795 gchar *str = strchr (cCommand, '%'); // search the first one.
1796 if (str != NULL)
1797 {
1798 if (str != cCommand && (*(str-1) == '"' || *(str-1) == '\'')) // take care of "" around the option.
1799 str --;
1800 *str = '\0'; // not a big deal if there are extras whitespaces at the end
1801 }
1802 }
1803 pMenuItem[1] = cCommand;
1804 pMenuItem[2] = g_key_file_get_string (pKeyFile, cGroup, "Icon", NULL);
1805
1806 pClassAppli->pMenuItems = g_list_append (pClassAppli->pMenuItems, pMenuItem);
1807 }
1808 g_free (cGroup);
1809 }
1810 g_strfreev (pMenuList);
1811 }
1812 }
1813
1814 /*
1815 register from desktop-file name/path (+class-name):
1816 if class-name: guess class -> lookup class -> if already registered => quit
1817 search complete path -> not found => abort
1818 get main info from file (Exec, StartupWMClass)
1819 if class-name NULL: guess class from Exec+StartupWMClass
1820 if already registered => quit
1821 make new class
1822 get additional params from file (MimeType, Icon, etc) and store them in the class
1823
1824 register from class name (window or old launchers):
1825 guess class -> lookup class -> if already registered => quit
1826 search complete path -> not found => abort
1827 make new class
1828 get additional params from file (MimeType, Icon, etc) and store them in the class
1829 */
cairo_dock_register_class_full(const gchar * cDesktopFile,const gchar * cClassName,const gchar * cWmClass)1830 gchar *cairo_dock_register_class_full (const gchar *cDesktopFile, const gchar *cClassName, const gchar *cWmClass)
1831 {
1832 g_return_val_if_fail (cDesktopFile != NULL || cClassName != NULL, NULL);
1833 //g_print ("%s (%s, %s, %s)\n", __func__, cDesktopFile, cClassName, cWmClass);
1834
1835 //\__________________ if the class is already registered and filled, quit.
1836 gchar *cClass = NULL;
1837 if (cClassName != NULL)
1838 cClass = cairo_dock_guess_class (NULL, cClassName);
1839 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass?cClass:cDesktopFile);
1840
1841 if (pClassAppli != NULL && pClassAppli->bSearchedAttributes && pClassAppli->cDesktopFile) // we already searched this class, and we did find its .desktop file, so let's end here.
1842 {
1843 //g_print ("class %s already known (%s)\n", cClass?cClass:cDesktopFile, pClassAppli->cDesktopFile);
1844 if (pClassAppli->cStartupWMClass == NULL && cWmClass != NULL) // if the cStartupWMClass was not defined in the .desktop file, store it now.
1845 pClassAppli->cStartupWMClass = g_strdup (cWmClass);
1846 //g_print ("%s --> %s\n", cClass, pClassAppli->cStartupWMClass);
1847 return (cClass?cClass:g_strdup (cDesktopFile));
1848 }
1849
1850 //\__________________ search the desktop file's path.
1851 gchar *cDesktopFilePath = _search_desktop_file (cDesktopFile?cDesktopFile:cClass);
1852 if (cDesktopFilePath == NULL) // couldn't find the .desktop
1853 {
1854 if (cClass != NULL) // make a class anyway to store the few info we have.
1855 {
1856 if (pClassAppli == NULL)
1857 pClassAppli = cairo_dock_get_class (cClass);
1858 if (pClassAppli != NULL)
1859 {
1860 if (pClassAppli->cStartupWMClass == NULL && cWmClass != NULL)
1861 pClassAppli->cStartupWMClass = g_strdup (cWmClass);
1862 //g_print ("%s ---> %s\n", cClass, pClassAppli->cStartupWMClass);
1863 pClassAppli->bSearchedAttributes = TRUE;
1864 }
1865 }
1866 cd_debug ("couldn't find the desktop file %s", cDesktopFile?cDesktopFile:cClass);
1867 return cClass; /// NULL
1868 }
1869
1870 //\__________________ open it.
1871 cd_debug ("+ parsing class desktop file %s...", cDesktopFilePath);
1872 GKeyFile* pKeyFile = cairo_dock_open_key_file (cDesktopFilePath);
1873 g_return_val_if_fail (pKeyFile != NULL, NULL);
1874
1875 //\__________________ guess the class name.
1876 gchar *cCommand = g_key_file_get_string (pKeyFile, "Desktop Entry", "Exec", NULL);
1877 gchar *cStartupWMClass = g_key_file_get_string (pKeyFile, "Desktop Entry", "StartupWMClass", NULL);
1878 if (cStartupWMClass && *cStartupWMClass == '\0')
1879 {
1880 g_free (cStartupWMClass);
1881 cStartupWMClass = NULL;
1882 }
1883 if (cClass == NULL)
1884 cClass = cairo_dock_guess_class (cCommand, cStartupWMClass);
1885 if (cClass == NULL)
1886 {
1887 cd_debug ("couldn't guess the class for %s", cDesktopFile);
1888 g_free (cDesktopFilePath);
1889 g_free (cCommand);
1890 g_free (cStartupWMClass);
1891 return NULL;
1892 }
1893
1894 //\__________________ make a new class or get the existing one.
1895 pClassAppli = cairo_dock_get_class (cClass);
1896 g_return_val_if_fail (pClassAppli!= NULL, NULL);
1897
1898 //\__________________ if we already searched and found the attributes beforehand, quit.
1899 if (pClassAppli->bSearchedAttributes && pClassAppli->cDesktopFile)
1900 {
1901 if (pClassAppli->cStartupWMClass == NULL && cWmClass != NULL) // we already searched this class before, but we couldn't have its WM class.
1902 pClassAppli->cStartupWMClass = g_strdup (cWmClass);
1903 //g_print ("%s ----> %s\n", cClass, pClassAppli->cStartupWMClass);
1904 g_free (cDesktopFilePath);
1905 g_free (cCommand);
1906 g_free (cStartupWMClass);
1907 return cClass;
1908 }
1909 pClassAppli->bSearchedAttributes = TRUE;
1910
1911 //\__________________ get the attributes.
1912 pClassAppli->cDesktopFile = cDesktopFilePath;
1913
1914 pClassAppli->cName = cairo_dock_get_locale_string_from_conf_file (pKeyFile, "Desktop Entry", "Name", NULL);
1915
1916 if (cCommand != NULL) // remove the launching options %x.
1917 {
1918 gchar *str = strchr (cCommand, '%'); // search the first one.
1919
1920 if (str && *(str+1) == 'c') // this one (caption) is the only one that is expected (ex.: kreversi -caption "%c"; if we let '-caption' with nothing after, the appli will melt down); others are either URL or icon that can be empty as per the freedesktop specs, so we can sefely remove them completely from the command line.
1921 {
1922 *str = '\0';
1923 gchar *cmd2 = g_strdup_printf ("%s%s%s", cCommand, pClassAppli->cName, str+2); // replace %c with the localized name.
1924 g_free (cCommand);
1925 cCommand = cmd2;
1926 str = strchr (cCommand, '%'); // jump to the next one.
1927 }
1928
1929 if (str != NULL) // remove everything from the first option to the end.
1930 {
1931 if (str != cCommand && (*(str-1) == '"' || *(str-1) == '\'')) // take care of "" around the option.
1932 str --;
1933 *str = '\0'; // not a big deal if there are extras whitespaces at the end.
1934 }
1935 }
1936 pClassAppli->cCommand = cCommand;
1937
1938 if (pClassAppli->cStartupWMClass == NULL)
1939 pClassAppli->cStartupWMClass = (cStartupWMClass ? cStartupWMClass : g_strdup (cWmClass));
1940 //g_print ("%s -> pClassAppli->cStartupWMClass: %s\n", cClass, pClassAppli->cStartupWMClass);
1941
1942 pClassAppli->cIcon = g_key_file_get_string (pKeyFile, "Desktop Entry", "Icon", NULL);
1943 if (pClassAppli->cIcon != NULL && *pClassAppli->cIcon != '/') // remove any extension.
1944 {
1945 gchar *str = strrchr (pClassAppli->cIcon, '.');
1946 if (str && (strcmp (str+1, "png") == 0 || strcmp (str+1, "svg") == 0 || strcmp (str+1, "xpm") == 0))
1947 *str = '\0';
1948 }
1949
1950 gsize length = 0;
1951 pClassAppli->pMimeTypes = g_key_file_get_string_list (pKeyFile, "Desktop Entry", "MimeType", &length, NULL);
1952
1953 pClassAppli->cWorkingDirectory = g_key_file_get_string (pKeyFile, "Desktop Entry", "Path", NULL);
1954
1955 pClassAppli->bHasStartupNotify = g_key_file_get_boolean (pKeyFile, "Desktop Entry", "StartupNotify", NULL); // let's handle the case StartupNotify=false as if the key was absent (ie: rely on the window events to stop the launching)
1956
1957 //\__________________ Gettext domain
1958 // The translations of the quicklist menus are generally available in a .mo file
1959 gchar *cGettextDomain = g_key_file_get_string (pKeyFile, "Desktop Entry", "X-Ubuntu-Gettext-Domain", NULL);
1960 if (cGettextDomain == NULL)
1961 cGettextDomain = g_key_file_get_string (pKeyFile, "Desktop Entry", "X-GNOME-Gettext-Domain", NULL); // Yes, they like doing that :P
1962 // a few time ago, it seems that it was 'X-Gettext-Domain'
1963
1964 //______________ Quicklist menus.
1965 _add_action_menus (pKeyFile, pClassAppli, cGettextDomain, "X-Ayatana-Desktop-Shortcuts", "Shortcut Group", TRUE); // oh crap, with a name like that you can be sure it will change 25 times before they decide a definite name :-/
1966 _add_action_menus (pKeyFile, pClassAppli, cGettextDomain, "Actions", "Desktop Action", FALSE); // yes, it's true ^^ => Ubuntu Quantal
1967
1968 g_free (cGettextDomain);
1969
1970 g_key_file_free (pKeyFile);
1971 cd_debug (" -> class '%s'", cClass);
1972 return cClass;
1973 }
1974
cairo_dock_set_data_from_class(const gchar * cClass,Icon * pIcon)1975 void cairo_dock_set_data_from_class (const gchar *cClass, Icon *pIcon)
1976 {
1977 g_return_if_fail (cClass != NULL && pIcon != NULL);
1978 cd_debug ("%s (%s)", __func__, cClass);
1979
1980 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
1981 if (pClassAppli == NULL || ! pClassAppli->bSearchedAttributes)
1982 {
1983 cd_debug ("no class %s or no attributes", cClass);
1984 return;
1985 }
1986
1987 if (pIcon->cCommand == NULL)
1988 pIcon->cCommand = g_strdup (pClassAppli->cCommand);
1989
1990 if (pIcon->cWorkingDirectory == NULL)
1991 pIcon->cWorkingDirectory = g_strdup (pClassAppli->cWorkingDirectory);
1992
1993 if (pIcon->cName == NULL)
1994 pIcon->cName = g_strdup (pClassAppli->cName);
1995
1996 if (pIcon->cFileName == NULL)
1997 pIcon->cFileName = g_strdup (pClassAppli->cIcon);
1998
1999 if (pIcon->pMimeTypes == NULL)
2000 pIcon->pMimeTypes = g_strdupv ((gchar**)pClassAppli->pMimeTypes);
2001 }
2002
2003
2004
_stop_opening_timeout(const gchar * cClass)2005 static gboolean _stop_opening_timeout (const gchar *cClass)
2006 {
2007 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
2008 g_return_val_if_fail (pClassAppli != NULL, FALSE);
2009 pClassAppli->iSidOpeningTimeout = 0;
2010 gldi_class_startup_notify_end (cClass);
2011 return FALSE;
2012 }
gldi_class_startup_notify(Icon * pIcon)2013 void gldi_class_startup_notify (Icon *pIcon)
2014 {
2015 const gchar *cClass = pIcon->cClass;
2016 CairoDockClassAppli *pClassAppli = cairo_dock_get_class (cClass);
2017 if (! pClassAppli || pClassAppli->bIsLaunching)
2018 return;
2019
2020 // mark the class as launching and set a timeout
2021 pClassAppli->bIsLaunching = TRUE;
2022 if (pClassAppli->iSidOpeningTimeout == 0)
2023 pClassAppli->iSidOpeningTimeout = g_timeout_add_seconds (15, // 15 seconds, for applications that take a really long time to start
2024 (GSourceFunc) _stop_opening_timeout, g_strdup (cClass)); /// TODO: there is a memory leak here...
2025
2026 // notify about the startup
2027 gldi_desktop_notify_startup (cClass);
2028
2029 // mark the icon as launching (this is just for convenience for the animations)
2030 gldi_icon_mark_as_launching (pIcon);
2031 }
2032
gldi_class_startup_notify_end(const gchar * cClass)2033 void gldi_class_startup_notify_end (const gchar *cClass)
2034 {
2035 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
2036 if (! pClassAppli || ! pClassAppli->bIsLaunching)
2037 return;
2038
2039 // unset the icons as launching
2040 GList* ic;
2041 Icon *icon;
2042 for (ic = pClassAppli->pIconsOfClass; ic != NULL; ic = ic->next)
2043 {
2044 icon = ic->data;
2045 gldi_icon_stop_marking_as_launching (icon);
2046 }
2047 for (ic = pClassAppli->pAppliOfClass; ic != NULL; ic = ic->next)
2048 {
2049 icon = ic->data;
2050 gldi_icon_stop_marking_as_launching (icon);
2051 }
2052
2053 // unset the class as launching and stop a timeout
2054 pClassAppli->bIsLaunching = FALSE;
2055 if (pClassAppli->iSidOpeningTimeout != 0)
2056 {
2057 g_source_remove (pClassAppli->iSidOpeningTimeout);
2058 pClassAppli->iSidOpeningTimeout = 0;
2059 }
2060 }
2061
gldi_class_is_starting(const gchar * cClass)2062 gboolean gldi_class_is_starting (const gchar *cClass)
2063 {
2064 CairoDockClassAppli *pClassAppli = _cairo_dock_lookup_class_appli (cClass);
2065 return (pClassAppli != NULL && pClassAppli->iSidOpeningTimeout != 0);
2066 }
2067