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