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-desktop-manager.h"  // g_desktopGeometry
22 #define _MANAGER_DEF_
23 #include "cairo-dock-windows-manager.h"
24 
25 // public (manager, config, data)
26 GldiObjectManager myWindowObjectMgr;
27 
28 // dependancies
29 
30 // private
31 GList *s_pWindowsList = NULL;  // list of all window actors
32 static gboolean s_bSortedByZ = FALSE;  // whether the list is currently sorted by z-order
33 static gboolean s_bSortedByAge = FALSE;  // whether the list is currently sorted by age
34 static GldiWindowManagerBackend s_backend;
35 
36 
on_zorder_changed(G_GNUC_UNUSED gpointer data)37 static gboolean on_zorder_changed (G_GNUC_UNUSED gpointer data)
38 {
39 	s_bSortedByZ = FALSE;  // invalidate the sorting
40 	return GLDI_NOTIFICATION_LET_PASS;
41 }
42 
_compare_z_order(GldiWindowActor * actor1,GldiWindowActor * actor2)43 static int _compare_z_order (GldiWindowActor *actor1, GldiWindowActor *actor2)
44 {
45 	if (actor1->iStackOrder < actor2->iStackOrder)
46 		return -1;
47 	else if (actor1->iStackOrder > actor2->iStackOrder)
48 		return 1;
49 	else
50 		return 0;
51 }
52 
_compare_age(GldiWindowActor * actor1,GldiWindowActor * actor2)53 static int _compare_age (GldiWindowActor *actor1, GldiWindowActor *actor2)
54 {
55 	if (actor1->iAge < actor2->iAge)
56 		return -1;
57 	else if (actor1->iAge > actor2->iAge)
58 		return 1;
59 	else
60 		return 0;
61 }
62 
gldi_windows_foreach(gboolean bOrderedByZ,GFunc callback,gpointer data)63 void gldi_windows_foreach (gboolean bOrderedByZ, GFunc callback, gpointer data)
64 {
65 	if (bOrderedByZ && ! s_bSortedByZ)
66 	{
67 		s_pWindowsList = g_list_sort (s_pWindowsList, (GCompareFunc)_compare_z_order);
68 		s_bSortedByZ = TRUE;
69 		s_bSortedByAge = FALSE;
70 	}
71 	else if (! bOrderedByZ && ! s_bSortedByAge)
72 	{
73 		s_pWindowsList = g_list_sort (s_pWindowsList, (GCompareFunc)_compare_age);
74 		s_bSortedByAge = TRUE;
75 		s_bSortedByZ = FALSE;
76 	}
77 	g_list_foreach (s_pWindowsList, callback, data);
78 }
79 
gldi_windows_find(gboolean (* callback)(GldiWindowActor *,gpointer),gpointer data)80 GldiWindowActor *gldi_windows_find (gboolean (*callback) (GldiWindowActor*, gpointer), gpointer data)
81 {
82 	GldiWindowActor *actor;
83 	GList *a;
84 	for (a = s_pWindowsList; a != NULL; a = a->next)
85 	{
86 		actor = a->data;
87 		if (callback (actor, data))
88 			return actor;
89 	}
90 	return NULL;
91 }
92 
93 
94   ///////////////
95  /// BACKEND ///
96 ///////////////
97 
gldi_windows_manager_register_backend(GldiWindowManagerBackend * pBackend)98 void gldi_windows_manager_register_backend (GldiWindowManagerBackend *pBackend)
99 {
100 	gpointer *ptr = (gpointer*)&s_backend;
101 	gpointer *src = (gpointer*)pBackend;
102 	gpointer *src_end = (gpointer*)(pBackend + 1);
103 	while (src != src_end)
104 	{
105 		if (*src != NULL)
106 			*ptr = *src;
107 		src ++;
108 		ptr ++;
109 	}
110 }
111 
gldi_window_move_to_desktop(GldiWindowActor * actor,int iNumDesktop,int iNumViewportX,int iNumViewportY)112 void gldi_window_move_to_desktop (GldiWindowActor *actor, int iNumDesktop, int iNumViewportX, int iNumViewportY)
113 {
114 	g_return_if_fail (actor != NULL);
115 	if (s_backend.move_to_nth_desktop)
116 		s_backend.move_to_nth_desktop (actor,
117 			iNumDesktop,
118 			(iNumViewportX - g_desktopGeometry.iCurrentViewportX) * gldi_desktop_get_width(),
119 			(iNumViewportY - g_desktopGeometry.iCurrentViewportY) * gldi_desktop_get_height());
120 }
121 
gldi_window_show(GldiWindowActor * actor)122 void gldi_window_show (GldiWindowActor *actor)
123 {
124 	g_return_if_fail (actor != NULL);
125 	if (s_backend.show)
126 		s_backend.show (actor);
127 }
128 
129 
gldi_window_close(GldiWindowActor * actor)130 void gldi_window_close (GldiWindowActor *actor)
131 {
132 	g_return_if_fail (actor != NULL);
133 	if (s_backend.close)
134 		s_backend.close (actor);
135 }
136 
gldi_window_kill(GldiWindowActor * actor)137 void gldi_window_kill (GldiWindowActor *actor)
138 {
139 	g_return_if_fail (actor != NULL);
140 	if (s_backend.kill)
141 		s_backend.kill (actor);
142 }
143 
gldi_window_minimize(GldiWindowActor * actor)144 void gldi_window_minimize (GldiWindowActor *actor)
145 {
146 	g_return_if_fail (actor != NULL);
147 	if (s_backend.minimize)
148 		s_backend.minimize (actor);
149 }
150 
gldi_window_lower(GldiWindowActor * actor)151 void gldi_window_lower (GldiWindowActor *actor)
152 {
153 	g_return_if_fail (actor != NULL);
154 	if (s_backend.lower)
155 		s_backend.lower (actor);
156 }
157 
gldi_window_maximize(GldiWindowActor * actor,gboolean bMaximize)158 void gldi_window_maximize (GldiWindowActor *actor, gboolean bMaximize)
159 {
160 	g_return_if_fail (actor != NULL);
161 	if (s_backend.maximize)
162 		s_backend.maximize (actor, bMaximize);
163 }
164 
gldi_window_set_fullscreen(GldiWindowActor * actor,gboolean bFullScreen)165 void gldi_window_set_fullscreen (GldiWindowActor *actor, gboolean bFullScreen)
166 {
167 	g_return_if_fail (actor != NULL);
168 	if (s_backend.set_fullscreen)
169 		s_backend.set_fullscreen (actor, bFullScreen);
170 }
171 
gldi_window_set_above(GldiWindowActor * actor,gboolean bAbove)172 void gldi_window_set_above (GldiWindowActor *actor, gboolean bAbove)
173 {
174 	g_return_if_fail (actor != NULL);
175 	if (s_backend.set_above)
176 		s_backend.set_above (actor, bAbove);
177 }
178 
gldi_window_set_minimize_position(GldiWindowActor * actor,int x,int y)179 void gldi_window_set_minimize_position (GldiWindowActor *actor, int x, int y)
180 {
181 	g_return_if_fail (actor != NULL);
182 	if (s_backend.set_minimize_position)
183 		s_backend.set_minimize_position (actor, x, y);
184 }
185 
gldi_window_set_thumbnail_area(GldiWindowActor * actor,int x,int y,int w,int h)186 void gldi_window_set_thumbnail_area (GldiWindowActor *actor, int x, int y, int w, int h)
187 {
188 	g_return_if_fail (actor != NULL);
189 	if (s_backend.set_thumbnail_area)
190 		s_backend.set_thumbnail_area (actor, x, y, w, h);
191 }
192 
gldi_windows_get_active(void)193 GldiWindowActor *gldi_windows_get_active (void)
194 {
195 	if (s_backend.get_active_window)
196 		return s_backend.get_active_window ();
197 	return NULL;
198 }
199 
gldi_window_set_border(GldiWindowActor * actor,gboolean bWithBorder)200 void gldi_window_set_border (GldiWindowActor *actor, gboolean bWithBorder)
201 {
202 	if (s_backend.set_window_border)
203 		s_backend.set_window_border (actor, bWithBorder);
204 }
205 
gldi_window_get_icon_surface(GldiWindowActor * actor,int iWidth,int iHeight)206 cairo_surface_t *gldi_window_get_icon_surface (GldiWindowActor *actor, int iWidth, int iHeight)
207 {
208 	g_return_val_if_fail (actor != NULL, NULL);
209 	if (s_backend.get_icon_surface)
210 		return s_backend.get_icon_surface (actor, iWidth, iHeight);
211 	return NULL;
212 }
213 
gldi_window_get_thumbnail_surface(GldiWindowActor * actor,int iWidth,int iHeight)214 cairo_surface_t *gldi_window_get_thumbnail_surface (GldiWindowActor *actor, int iWidth, int iHeight)
215 {
216 	g_return_val_if_fail (actor != NULL, NULL);
217 	if (s_backend.get_thumbnail_surface)
218 		return s_backend.get_thumbnail_surface (actor, iWidth, iHeight);
219 	return NULL;
220 }
221 
gldi_window_get_texture(GldiWindowActor * actor)222 GLuint gldi_window_get_texture (GldiWindowActor *actor)
223 {
224 	g_return_val_if_fail (actor != NULL, 0);
225 	if (s_backend.get_texture)
226 		return s_backend.get_texture (actor);
227 	return 0;
228 }
229 
gldi_window_get_transient_for(GldiWindowActor * actor)230 GldiWindowActor *gldi_window_get_transient_for (GldiWindowActor *actor)
231 {
232 	g_return_val_if_fail (actor != NULL, NULL);
233 	if (s_backend.get_transient_for)
234 		return s_backend.get_transient_for (actor);
235 	return NULL;
236 }
237 
gldi_window_is_above_or_below(GldiWindowActor * actor,gboolean * bIsAbove,gboolean * bIsBelow)238 void gldi_window_is_above_or_below (GldiWindowActor *actor, gboolean *bIsAbove, gboolean *bIsBelow)
239 {
240 	if (s_backend.set_window_border)
241 		s_backend.is_above_or_below (actor, bIsAbove, bIsBelow);
242 	else
243 	{
244 		*bIsAbove = FALSE;
245 		*bIsBelow = FALSE;
246 	}
247 }
248 
gldi_window_is_sticky(GldiWindowActor * actor)249 gboolean gldi_window_is_sticky (GldiWindowActor *actor)
250 {
251 	if (s_backend.is_sticky)
252 		return s_backend.is_sticky (actor);
253 	return FALSE;
254 }
255 
gldi_window_set_sticky(GldiWindowActor * actor,gboolean bSticky)256 void gldi_window_set_sticky (GldiWindowActor *actor, gboolean bSticky)
257 {
258 	if (s_backend.set_sticky)
259 		s_backend.set_sticky (actor, bSticky);
260 }
261 
gldi_window_can_minimize_maximize_close(GldiWindowActor * actor,gboolean * bCanMinimize,gboolean * bCanMaximize,gboolean * bCanClose)262 void gldi_window_can_minimize_maximize_close (GldiWindowActor *actor, gboolean *bCanMinimize, gboolean *bCanMaximize, gboolean *bCanClose)
263 {
264 	if (s_backend.can_minimize_maximize_close)
265 		s_backend.can_minimize_maximize_close (actor, bCanMinimize, bCanMaximize, bCanClose);
266 	else  // assume that the window can mnimize/maximize/close (default behavior)
267 	{
268 		*bCanMinimize = TRUE;
269 		*bCanMaximize = TRUE;
270 		*bCanClose = TRUE;
271 	}
272 }
273 
gldi_window_get_id(GldiWindowActor * actor)274 guint gldi_window_get_id (GldiWindowActor *actor)
275 {
276 	if (actor && s_backend.get_id)
277 		return s_backend.get_id (actor);
278 	return 0;
279 }
280 
gldi_window_pick(void)281 GldiWindowActor *gldi_window_pick (void)
282 {
283 	if (s_backend.pick_window)
284 		return s_backend.pick_window ();
285 	return NULL;
286 }
287 
288 
289   /////////////////
290  /// UTILITIES ///
291 /////////////////
292 
_window_is_on_current_desktop(GtkAllocation * pWindowGeometry,int iWindowDesktopNumber)293 static inline gboolean _window_is_on_current_desktop (GtkAllocation *pWindowGeometry, int iWindowDesktopNumber)
294 {
295 	int iGlobalPositionX, iGlobalPositionY, iWidthExtent, iHeightExtent;  // coordonnees du coin haut gauche dans le referentiel du viewport actuel.
296 	iGlobalPositionX = pWindowGeometry->x;
297 	iGlobalPositionY = pWindowGeometry->y;
298 	iWidthExtent = pWindowGeometry->width;
299 	iHeightExtent = pWindowGeometry->height;
300 
301 	return ( (iWindowDesktopNumber == g_desktopGeometry.iCurrentDesktop || iWindowDesktopNumber == -1) &&
302 		iGlobalPositionX + iWidthExtent > 0 &&
303 		iGlobalPositionX < gldi_desktop_get_width() &&
304 		iGlobalPositionY + iHeightExtent > 0 &&
305 		iGlobalPositionY < gldi_desktop_get_height() );
306 }
gldi_window_is_on_current_desktop(GldiWindowActor * actor)307 gboolean gldi_window_is_on_current_desktop (GldiWindowActor *actor)
308 {
309 	///return (actor->iNumDesktop == -1 || actor->iNumDesktop == g_desktopGeometry.iCurrentDesktop) && actor->iViewPortX == g_desktopGeometry.iCurrentViewportX && actor->iViewPortY == g_desktopGeometry.iCurrentViewportY;  /// TODO: check that it works
310 	return _window_is_on_current_desktop (&actor->windowGeometry, actor->iNumDesktop);
311 }
312 
313 
gldi_window_is_on_desktop(GldiWindowActor * pAppli,int iNumDesktop,int iNumViewportX,int iNumViewportY)314 gboolean gldi_window_is_on_desktop (GldiWindowActor *pAppli, int iNumDesktop, int iNumViewportX, int iNumViewportY)
315 {
316 	// On calcule les coordonnees en repere absolu.
317 	int x = pAppli->windowGeometry.x;  // par rapport au viewport courant.
318 	x += g_desktopGeometry.iCurrentViewportX * gldi_desktop_get_width();  // repere absolu
319 	if (x < 0)
320 		x += g_desktopGeometry.iNbViewportX * gldi_desktop_get_width();
321 	int y = pAppli->windowGeometry.y;
322 	y += g_desktopGeometry.iCurrentViewportY * gldi_desktop_get_height();
323 	if (y < 0)
324 		y += g_desktopGeometry.iNbViewportY * gldi_desktop_get_height();
325 	int w = pAppli->windowGeometry.width, h = pAppli->windowGeometry.height;
326 
327 	// test d'intersection avec le viewport donne.
328 	return ((pAppli->iNumDesktop == -1 || pAppli->iNumDesktop == iNumDesktop) &&
329 		x + w > iNumViewportX * gldi_desktop_get_width() &&
330 		x < (iNumViewportX + 1) * gldi_desktop_get_width() &&
331 		y + h > iNumViewportY * gldi_desktop_get_height() &&
332 		y < (iNumViewportY + 1) * gldi_desktop_get_height());
333 }
334 
gldi_window_move_to_current_desktop(GldiWindowActor * pAppli)335 void gldi_window_move_to_current_desktop (GldiWindowActor *pAppli)
336 {
337 	gldi_window_move_to_desktop (pAppli,
338 		g_desktopGeometry.iCurrentDesktop,
339 		g_desktopGeometry.iCurrentViewportX,
340 		g_desktopGeometry.iCurrentViewportY);  // on ne veut pas decaler son viewport par rapport a nous.
341 }
342 
343 
344   ///////////////
345  /// MANAGER ///
346 ///////////////
347 
init_object(GldiObject * obj,G_GNUC_UNUSED gpointer attr)348 static void init_object (GldiObject *obj, G_GNUC_UNUSED gpointer attr)
349 {
350 	GldiWindowActor *actor = (GldiWindowActor*)obj;
351 	s_pWindowsList = g_list_prepend (s_pWindowsList, actor);
352 }
353 
reset_object(GldiObject * obj)354 static void reset_object (GldiObject *obj)
355 {
356 	GldiWindowActor *actor = (GldiWindowActor*)obj;
357 	g_free (actor->cName);
358 	g_free (actor->cClass);
359 	g_free (actor->cWmClass);
360 	g_free (actor->cLastAttentionDemand);
361 	s_pWindowsList = g_list_remove (s_pWindowsList, actor);
362 }
363 
gldi_register_windows_manager(void)364 void gldi_register_windows_manager (void)
365 {
366 	// Object Manager
367 	memset (&myWindowObjectMgr, 0, sizeof (GldiObjectManager));
368 	myWindowObjectMgr.cName          = "WindowActor";
369 	myWindowObjectMgr.iObjectSize    = sizeof (GldiWindowActor);
370 	// interface
371 	myWindowObjectMgr.init_object    = init_object;
372 	myWindowObjectMgr.reset_object   = reset_object;
373 	// signals
374 	gldi_object_install_notifications (&myWindowObjectMgr, NB_NOTIFICATIONS_WINDOWS);
375 
376 	// init
377 	memset (&s_backend, 0, sizeof (GldiWindowManagerBackend));
378 	gldi_object_register_notification (&myWindowObjectMgr,
379 		NOTIFICATION_WINDOW_Z_ORDER_CHANGED,
380 		(GldiNotificationFunc) on_zorder_changed,
381 		GLDI_RUN_FIRST, NULL);
382 }
383 
384