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 "cairo-dock-log.h"
21 #include "cairo-dock-desklet-manager.h"  // cairo_dock_foreach_desklet
22 #include "cairo-dock-desklet-factory.h"
23 #include "cairo-dock-draw-opengl.h"  // cairo_dock_create_texture_from_surface
24 #include "cairo-dock-compiz-integration.h"
25 #include "cairo-dock-kwin-integration.h"
26 #include "cairo-dock-gnome-shell-integration.h"
27 #include "cairo-dock-cinnamon-integration.h"
28 #define _MANAGER_DEF_
29 #include "cairo-dock-desktop-manager.h"
30 
31 // public (manager, config, data)
32 GldiManager myDesktopMgr;
33 GldiDesktopGeometry g_desktopGeometry;
34 
35 // dependancies
36 extern GldiContainer *g_pPrimaryContainer;
37 
38 // private
39 static GldiDesktopBackground *s_pDesktopBg = NULL;  // une fois alloue, le pointeur restera le meme tout le temps.
40 static GldiDesktopManagerBackend s_backend;
41 
42 static void _reload_desktop_background (void);
43 
44 
45   //////////////////////
46  /// desktop access ///
47 //////////////////////
48 
gldi_desktop_get_current(int * iCurrentDesktop,int * iCurrentViewportX,int * iCurrentViewportY)49 void gldi_desktop_get_current (int *iCurrentDesktop, int *iCurrentViewportX, int *iCurrentViewportY)
50 {
51 	*iCurrentDesktop = g_desktopGeometry.iCurrentDesktop;
52 	*iCurrentViewportX = g_desktopGeometry.iCurrentViewportX;
53 	*iCurrentViewportY = g_desktopGeometry.iCurrentViewportY;
54 }
55 
56 
57   //////////////////////////////
58  /// DESKTOP MANAGER BACKEND ///
59 //////////////////////////////
60 
_set_desklets_on_widget_layer(CairoDesklet * pDesklet,G_GNUC_UNUSED gpointer data)61 static gboolean _set_desklets_on_widget_layer (CairoDesklet *pDesklet, G_GNUC_UNUSED gpointer data)
62 {
63 	if (pDesklet->iVisibility == CAIRO_DESKLET_ON_WIDGET_LAYER)
64 		gldi_desktop_set_on_widget_layer (CAIRO_CONTAINER (pDesklet), TRUE);
65 	return FALSE;  // continue
66 }
gldi_desktop_manager_register_backend(GldiDesktopManagerBackend * pBackend)67 void gldi_desktop_manager_register_backend (GldiDesktopManagerBackend *pBackend)
68 {
69 	gpointer *ptr = (gpointer*)&s_backend;
70 	gpointer *src = (gpointer*)pBackend;
71 	gpointer *src_end = (gpointer*)(pBackend + 1);
72 	while (src != src_end)
73 	{
74 		if (*src != NULL)
75 			*ptr = *src;
76 		src ++;
77 		ptr ++;
78 	}
79 
80 	// since we have a backend, set up the desklets that are supposed to be on the widget layer.
81 	if (s_backend.set_on_widget_layer != NULL)
82 	{
83 		gldi_desklets_foreach ((GldiDeskletForeachFunc) _set_desklets_on_widget_layer, NULL);
84 	}
85 }
86 
gldi_desktop_present_class(const gchar * cClass)87 gboolean gldi_desktop_present_class (const gchar *cClass)  // scale matching class
88 {
89 	g_return_val_if_fail (cClass != NULL, FALSE);
90 	if (s_backend.present_class != NULL)
91 	{
92 		return s_backend.present_class (cClass);
93 	}
94 	return FALSE;
95 }
96 
gldi_desktop_present_windows(void)97 gboolean gldi_desktop_present_windows (void)  // scale
98 {
99 	if (s_backend.present_windows != NULL)
100 	{
101 		return s_backend.present_windows ();
102 	}
103 	return FALSE;
104 }
105 
gldi_desktop_present_desktops(void)106 gboolean gldi_desktop_present_desktops (void)  // expose
107 {
108 	if (s_backend.present_desktops != NULL)
109 	{
110 		return s_backend.present_desktops ();
111 	}
112 	return FALSE;
113 }
114 
gldi_desktop_show_widget_layer(void)115 gboolean gldi_desktop_show_widget_layer (void)  // widget
116 {
117 	if (s_backend.show_widget_layer != NULL)
118 	{
119 		return s_backend.show_widget_layer ();
120 	}
121 	return FALSE;
122 }
123 
gldi_desktop_set_on_widget_layer(GldiContainer * pContainer,gboolean bOnWidgetLayer)124 gboolean gldi_desktop_set_on_widget_layer (GldiContainer *pContainer, gboolean bOnWidgetLayer)
125 {
126 	if (s_backend.set_on_widget_layer != NULL)
127 	{
128 		return s_backend.set_on_widget_layer (pContainer, bOnWidgetLayer);
129 	}
130 	return FALSE;
131 }
132 
gldi_desktop_can_present_class(void)133 gboolean gldi_desktop_can_present_class (void)
134 {
135 	return (s_backend.present_class != NULL);
136 }
137 
gldi_desktop_can_present_windows(void)138 gboolean gldi_desktop_can_present_windows (void)
139 {
140 	return (s_backend.present_windows != NULL);
141 }
142 
gldi_desktop_can_present_desktops(void)143 gboolean gldi_desktop_can_present_desktops (void)
144 {
145 	return (s_backend.present_desktops != NULL);
146 }
147 
gldi_desktop_can_show_widget_layer(void)148 gboolean gldi_desktop_can_show_widget_layer (void)
149 {
150 	return (s_backend.show_widget_layer != NULL);
151 }
152 
gldi_desktop_can_set_on_widget_layer(void)153 gboolean gldi_desktop_can_set_on_widget_layer (void)
154 {
155 	return (s_backend.set_on_widget_layer != NULL);
156 }
157 
158 
gldi_desktop_show_hide(gboolean bShow)159 gboolean gldi_desktop_show_hide (gboolean bShow)
160 {
161 	if (s_backend.show_hide_desktop)
162 	{
163 		s_backend.show_hide_desktop (bShow);
164 		return TRUE;
165 	}
166 	return FALSE;
167 }
gldi_desktop_is_visible(void)168 gboolean gldi_desktop_is_visible (void)
169 {
170 	if (s_backend.desktop_is_visible)
171 		return s_backend.desktop_is_visible ();
172 	return FALSE;  // default state = not visible
173 }
gldi_desktop_get_names(void)174 gchar** gldi_desktop_get_names (void)
175 {
176 	if (s_backend.get_desktops_names)
177 		return s_backend.get_desktops_names ();
178 	return NULL;
179 }
gldi_desktop_set_names(gchar ** cNames)180 gboolean gldi_desktop_set_names (gchar **cNames)
181 {
182 	if (s_backend.set_desktops_names)
183 		return s_backend.set_desktops_names (cNames);
184 	return FALSE;
185 }
186 
_get_desktop_bg_surface(void)187 static cairo_surface_t *_get_desktop_bg_surface (void)
188 {
189 	if (s_backend.get_desktop_bg_surface)
190 		return s_backend.get_desktop_bg_surface ();
191 	return NULL;
192 }
193 
gldi_desktop_set_current(int iDesktopNumber,int iViewportNumberX,int iViewportNumberY)194 gboolean gldi_desktop_set_current (int iDesktopNumber, int iViewportNumberX, int iViewportNumberY)
195 {
196 	if (s_backend.set_current_desktop)
197 		return s_backend.set_current_desktop (iDesktopNumber, iViewportNumberX, iViewportNumberY);
198 	return FALSE;
199 }
200 
gldi_desktop_set_nb_desktops(int iNbDesktops,int iNbViewportX,int iNbViewportY)201 gboolean gldi_desktop_set_nb_desktops (int iNbDesktops, int iNbViewportX, int iNbViewportY)
202 {
203 	if (s_backend.set_nb_desktops)
204 		return s_backend.set_nb_desktops (iNbDesktops, iNbViewportX, iNbViewportY);
205 	return FALSE;
206 }
207 
gldi_desktop_refresh(void)208 void gldi_desktop_refresh (void)
209 {
210 	if (s_backend.refresh)
211 		s_backend.refresh ();
212 }
213 
gldi_desktop_notify_startup(const gchar * cClass)214 void gldi_desktop_notify_startup (const gchar *cClass)
215 {
216 	if (s_backend.notify_startup)
217 		s_backend.notify_startup (cClass);
218 }
219 
gldi_desktop_grab_shortkey(guint keycode,guint modifiers,gboolean grab)220 gboolean gldi_desktop_grab_shortkey (guint keycode, guint modifiers, gboolean grab)
221 {
222 	if (s_backend.grab_shortkey)
223 		return s_backend.grab_shortkey (keycode, modifiers, grab);
224 	return FALSE;
225 }
226 
227   //////////////////
228  /// DESKTOP BG ///
229 //////////////////
230 
gldi_desktop_background_get(gboolean bWithTextureToo)231 GldiDesktopBackground *gldi_desktop_background_get (gboolean bWithTextureToo)
232 {
233 	//g_print ("%s (%d, %d)\n", __func__, bWithTextureToo, s_pDesktopBg?s_pDesktopBg->iRefCount:-1);
234 	if (s_pDesktopBg == NULL)
235 	{
236 		s_pDesktopBg = g_new0 (GldiDesktopBackground, 1);
237 	}
238 	if (s_pDesktopBg->pSurface == NULL)
239 	{
240 		s_pDesktopBg->pSurface = _get_desktop_bg_surface ();
241 	}
242 	if (s_pDesktopBg->iTexture == 0 && bWithTextureToo)
243 	{
244 		s_pDesktopBg->iTexture = cairo_dock_create_texture_from_surface (s_pDesktopBg->pSurface);
245 	}
246 
247 	s_pDesktopBg->iRefCount ++;
248 	if (s_pDesktopBg->iSidDestroyBg != 0)
249 	{
250 		//g_print ("cancel pending destroy\n");
251 		g_source_remove (s_pDesktopBg->iSidDestroyBg);
252 		s_pDesktopBg->iSidDestroyBg = 0;
253 	}
254 	return s_pDesktopBg;
255 }
256 
_destroy_bg(GldiDesktopBackground * pDesktopBg)257 static gboolean _destroy_bg (GldiDesktopBackground *pDesktopBg)
258 {
259 	//g_print ("%s ()\n", __func__);
260 	g_return_val_if_fail (pDesktopBg != NULL, 0);
261 	if (pDesktopBg->pSurface != NULL)
262 	{
263 		cairo_surface_destroy (pDesktopBg->pSurface);
264 		pDesktopBg->pSurface = NULL;
265 		//g_print ("--- surface destroyed\n");
266 	}
267 	if (pDesktopBg->iTexture != 0)
268 	{
269 		_cairo_dock_delete_texture (pDesktopBg->iTexture);
270 		pDesktopBg->iTexture = 0;
271 	}
272 	pDesktopBg->iSidDestroyBg = 0;
273 	return FALSE;
274 }
gldi_desktop_background_destroy(GldiDesktopBackground * pDesktopBg)275 void gldi_desktop_background_destroy (GldiDesktopBackground *pDesktopBg)
276 {
277 	//g_print ("%s ()\n", __func__);
278 	if (!pDesktopBg)
279 		return;
280 	if (pDesktopBg->iRefCount > 0)
281 		pDesktopBg->iRefCount --;
282 	if (pDesktopBg->iRefCount == 0 && pDesktopBg->iSidDestroyBg == 0)
283 	{
284 		//g_print ("add pending destroy\n");
285 		pDesktopBg->iSidDestroyBg = g_timeout_add_seconds (3, (GSourceFunc)_destroy_bg, pDesktopBg);
286 	}
287 }
288 
gldi_desktop_background_get_surface(GldiDesktopBackground * pDesktopBg)289 cairo_surface_t *gldi_desktop_background_get_surface (GldiDesktopBackground *pDesktopBg)
290 {
291 	g_return_val_if_fail (pDesktopBg != NULL, NULL);
292 	return pDesktopBg->pSurface;
293 }
294 
gldi_desktop_background_get_texture(GldiDesktopBackground * pDesktopBg)295 GLuint gldi_desktop_background_get_texture (GldiDesktopBackground *pDesktopBg)
296 {
297 	g_return_val_if_fail (pDesktopBg != NULL, 0);
298 	return pDesktopBg->iTexture;
299 }
300 
_reload_desktop_background(void)301 static void _reload_desktop_background (void)
302 {
303 	//g_print ("%s ()\n", __func__);
304 	if (s_pDesktopBg == NULL)  // rien a recharger.
305 		return ;
306 	if (s_pDesktopBg->pSurface == NULL && s_pDesktopBg->iTexture == 0)  // rien a recharger.
307 		return ;
308 
309 	if (s_pDesktopBg->pSurface != NULL)
310 	{
311 		cairo_surface_destroy (s_pDesktopBg->pSurface);
312 		//g_print ("--- surface destroyed\n");
313 	}
314 	s_pDesktopBg->pSurface = _get_desktop_bg_surface ();
315 
316 	if (s_pDesktopBg->iTexture != 0)
317 	{
318 		_cairo_dock_delete_texture (s_pDesktopBg->iTexture);
319 		s_pDesktopBg->iTexture = cairo_dock_create_texture_from_surface (s_pDesktopBg->pSurface);
320 	}
321 }
322 
323 
324   //////////////
325  /// UNLOAD ///
326 //////////////
327 
unload(void)328 static void unload (void)
329 {
330 	/*if (s_pDesktopBg != NULL && s_pDesktopBg->iTexture != 0)
331 	{
332 		_cairo_dock_delete_texture (s_pDesktopBg->iTexture);
333 		s_pDesktopBg->iTexture = 0;
334 	}*/
335 	if (s_pDesktopBg)  // on decharge le desktop-bg de force.
336 	{
337 		if (s_pDesktopBg->iSidDestroyBg != 0)
338 		{
339 			g_source_remove (s_pDesktopBg->iSidDestroyBg);
340 			s_pDesktopBg->iSidDestroyBg = 0;
341 		}
342 		s_pDesktopBg->iRefCount = 0;
343 		_destroy_bg (s_pDesktopBg);  // detruit ses ressources immediatement, mais pas le pointeur.
344 	}
345 }
346 
347 
on_wallpaper_changed(G_GNUC_UNUSED gpointer data)348 static gboolean on_wallpaper_changed (G_GNUC_UNUSED gpointer data)
349 {
350 	_reload_desktop_background ();
351 	return GLDI_NOTIFICATION_LET_PASS;
352 }
353 
354   ////////////
355  /// INIT ///
356 ////////////
357 
init(void)358 static void init (void)
359 {
360 	//\__________________ Init the Window Manager backends.
361 	cd_init_compiz_backend ();
362 	cd_init_kwin_backend ();
363 	cd_init_gnome_shell_backend ();
364 	cd_init_cinnamon_backend ();
365 }
366 
367 
368   ///////////////
369  /// MANAGER ///
370 ///////////////
371 
gldi_register_desktop_manager(void)372 void gldi_register_desktop_manager (void)
373 {
374 	// Manager
375 	memset (&myDesktopMgr, 0, sizeof (GldiManager));
376 	gldi_object_init (GLDI_OBJECT(&myDesktopMgr), &myManagerObjectMgr, NULL);
377 	myDesktopMgr.cModuleName  = "Desktop";
378 	// interface
379 	myDesktopMgr.init         = init;
380 	myDesktopMgr.load         = NULL;
381 	myDesktopMgr.unload       = unload;
382 	myDesktopMgr.reload       = (GldiManagerReloadFunc)NULL;
383 	myDesktopMgr.get_config   = (GldiManagerGetConfigFunc)NULL;
384 	myDesktopMgr.reset_config = (GldiManagerResetConfigFunc)NULL;
385 	// Config
386 	myDesktopMgr.pConfig = (GldiManagerConfigPtr)NULL;
387 	myDesktopMgr.iSizeOfConfig = 0;
388 	// data
389 	myDesktopMgr.iSizeOfData = 0;
390 	myDesktopMgr.pData = (GldiManagerDataPtr)NULL;
391 	memset (&s_backend, 0, sizeof (GldiDesktopManagerBackend));
392 	// signals
393 	gldi_object_install_notifications (&myDesktopMgr, NB_NOTIFICATIONS_DESKTOP);  // we don't have a Desktop Object, so let's put the signals here
394 
395 	// init
396 	gldi_object_register_notification (&myDesktopMgr,
397 		NOTIFICATION_DESKTOP_WALLPAPER_CHANGED,
398 		(GldiNotificationFunc) on_wallpaper_changed,
399 		GLDI_RUN_FIRST, NULL);
400 }
401 
402