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 <string.h>
21 #include <glib/gstdio.h>
22 #include <math.h>
23 
24 #include "applet-struct.h"
25 #include "applet-load-icons.h"
26 #include "applet-desktops.h"
27 #include "applet-draw.h"
28 
29 typedef struct {
30 	gint iNumDesktop;
31 	gint iNumViewportX;
32 	gint iNumViewportY;
33 	gint iOneViewportWidth;
34 	gint iOneViewportHeight;
35 	cairo_t *pCairoContext;
36 	} CDSwitcherDesktop;
37 
_cd_switcher_draw_windows_on_viewport(Icon * pIcon,CDSwitcherDesktop * data)38 static void _cd_switcher_draw_windows_on_viewport (Icon *pIcon, CDSwitcherDesktop *data)
39 {
40 	if (pIcon == NULL || pIcon->fInsertRemoveFactor > 0)
41 		return ;
42 	GldiWindowActor *actor = pIcon->pAppli;
43 	if (actor->bIsHidden && ! myConfig.bDisplayHiddenWindows)
44 		return ;
45 	int iNumDesktop = data->iNumDesktop;
46 	int iNumViewportX = data->iNumViewportX;
47 	int iNumViewportY = data->iNumViewportY;
48 	int iOneViewportWidth = data->iOneViewportWidth;
49 	int iOneViewportHeight = data->iOneViewportHeight;
50 	cairo_t *pCairoContext = data->pCairoContext;
51 
52 	// On calcule les coordonnees en repere absolu.
53 	int x = actor->windowGeometry.x;  // par rapport au viewport courant.
54 	x += myData.switcher.iCurrentViewportX * g_desktopGeometry.Xscreen.width;  // repere absolu
55 	if (x < 0)
56 		x += g_desktopGeometry.iNbViewportX * g_desktopGeometry.Xscreen.width;
57 	int y = actor->windowGeometry.y;
58 	y += myData.switcher.iCurrentViewportY * g_desktopGeometry.Xscreen.height;
59 	if (y < 0)
60 		y += g_desktopGeometry.iNbViewportY * g_desktopGeometry.Xscreen.height;
61 	int w = actor->windowGeometry.width, h = actor->windowGeometry.height;
62 
63 	// test d'intersection avec le viewport donne.
64 	//g_print (" %s : (%d;%d) %dx%d\n", pIcon->cName, x, y, w, h);
65 	if ((actor->iNumDesktop != -1 && actor->iNumDesktop != iNumDesktop) ||
66 		x + w <= iNumViewportX * g_desktopGeometry.Xscreen.width ||
67 		x >= (iNumViewportX + 1) * g_desktopGeometry.Xscreen.width ||
68 		y + h <= iNumViewportY * g_desktopGeometry.Xscreen.height ||
69 		y >= (iNumViewportY + 1) * g_desktopGeometry.Xscreen.height)
70 		return ;
71 
72 	// on dessine ses traits.
73 	cairo_save (pCairoContext);
74 
75 	GldiWindowActor *pActiveWindow = gldi_windows_get_active ();
76 
77 	if (myConfig.bFillAllWindows && actor != pActiveWindow)
78 		cairo_set_source_rgba (pCairoContext, myConfig.RGBWFillColors[0], myConfig.RGBWFillColors[1], myConfig.RGBWFillColors[2], myConfig.RGBWFillColors[3]);
79 	else
80 	{
81 		if (myConfig.bUseDefaultColors)
82 			gldi_style_colors_set_line_color (myDrawContext);
83 		else
84 			cairo_set_source_rgba (pCairoContext, myConfig.RGBWLineColors[0], myConfig.RGBWLineColors[1], myConfig.RGBWLineColors[2], myConfig.RGBWLineColors[3]);
85 	}
86 	cairo_rectangle (pCairoContext,
87 		(1.*x/g_desktopGeometry.Xscreen.width - iNumViewportX)*iOneViewportWidth,
88 		(1.*y/g_desktopGeometry.Xscreen.height - iNumViewportY)*iOneViewportHeight,
89 		1.*w/g_desktopGeometry.Xscreen.width*iOneViewportWidth,
90 		1.*h/g_desktopGeometry.Xscreen.height*iOneViewportHeight);
91 
92 	if (myConfig.bFillAllWindows || actor == pActiveWindow)
93 	{
94 		//g_print (" %s est la fenetre active\n", pIcon->cName);
95 		cairo_fill (pCairoContext);
96 	}
97 	else
98 	{
99 		cairo_stroke (pCairoContext);
100 	}
101 
102 	if (myConfig.bDrawIcons)
103 	{
104 		const CairoDockImageBuffer *pImage = gldi_appli_icon_get_image_buffer (pIcon);
105 		if (pImage && pImage->pSurface)
106 		{
107 			double fZoomX = (double) w/g_desktopGeometry.Xscreen.width*iOneViewportWidth / pImage->iWidth;
108 			double fZoomY = (double) h/g_desktopGeometry.Xscreen.height*iOneViewportHeight / pImage->iHeight;
109 			double fZoom = MIN (fZoomX, fZoomY);  // on garde le ratio.
110 
111 			cairo_translate (pCairoContext,
112 				(1.*x/g_desktopGeometry.Xscreen.width - iNumViewportX)*iOneViewportWidth + (fZoomX - fZoom) * pImage->iWidth/2,
113 				(1.*y/g_desktopGeometry.Xscreen.height - iNumViewportY)*iOneViewportHeight + (fZoomY - fZoom) * pImage->iHeight/2);
114 			cairo_scale (pCairoContext,
115 				fZoom,
116 				fZoom);
117 			cairo_set_source_surface (pCairoContext,
118 				pImage->pSurface,
119 				0.,
120 				0.);
121 			cairo_paint (pCairoContext);
122 		}
123 	}
124 
125 	cairo_restore (pCairoContext);
126 }
127 
128 
_compare_icons_stack_order(Icon * icon1,Icon * icon2)129 static int _compare_icons_stack_order (Icon *icon1, Icon *icon2)
130 {
131 	if (icon1 == NULL)  // les icones nulles vont a la fin.
132 		return 1;
133 	if (icon2 == NULL)
134 		return -1;
135 	if (icon1->pAppli->iStackOrder < icon2->pAppli->iStackOrder)  // ordre petit => dessus => dessinee en dernier.
136 		return -1;
137 	else
138 		return 1;
139 }
cd_switcher_draw_main_icon_compact_mode(void)140 void cd_switcher_draw_main_icon_compact_mode (void)
141 {
142 	if (myData.switcher.iNbColumns == 0 || myData.switcher.iNbLines == 0)  // may happen in desklet mode with a cube desktop, when the desklet is still 0x0.
143 		return;
144 	CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN_CAIRO ();
145 	///g_return_if_fail (myDrawContext != NULL);
146 	//g_print ("%s (%d;%d)\n", __func__, myData.switcher.iCurrentLine, myData.switcher.iCurrentColumn);
147 	// On efface l'icone.
148 	///cairo_dock_erase_cairo_context (myDrawContext);
149 
150 	// definition des parametres de dessin.
151 	int iWidth, iHeight;
152 	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
153 
154 	myData.switcher.fOneViewportHeight = (double) (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
155 	myData.switcher.fOneViewportWidth = (double) (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.
156 	double dx=0, dy=0;
157 	double w = iWidth, h = iHeight;
158 	if (myConfig.bPreserveScreenRatio)
159 	{
160 		double r = (double) g_desktopGeometry.Xscreen.width / g_desktopGeometry.Xscreen.height;
161 		double r_ = myData.switcher.fOneViewportWidth / myData.switcher.fOneViewportHeight;
162 		if (r_ > r)  // on etire trop en largeur.
163 		{
164 			myData.switcher.fOneViewportWidth /= r_ / r;
165 			w = myData.switcher.fOneViewportWidth * myData.switcher.iNbColumns + 2 * myConfig.iLineSize + (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize;
166 			dx = (double) (iWidth - w) / 2;
167 		}
168 		else
169 		{
170 			myData.switcher.fOneViewportHeight /= r / r_;
171 			h = myData.switcher.fOneViewportHeight * myData.switcher.iNbLines + 2 * myConfig.iLineSize + (myData.switcher.iNbLines - 1) * myConfig.iInLineSize;
172 			dy = (iHeight - h) / 2;
173 		}
174 	}
175 	myData.switcher.fOffsetX = dx;
176 	myData.switcher.fOffsetY = dy;
177 
178 	cairo_save (myDrawContext);
179 	cairo_translate (myDrawContext, dx, dy);
180 
181 	cairo_surface_t *pSurface = NULL;
182 	double fZoomX, fZoomY;
183 	if (myConfig.iIconDrawing == SWICTHER_MAP_WALLPAPER)
184 	{
185 		pSurface = myData.pDesktopBgMapSurface;
186 	}
187 	if (pSurface == NULL)
188 	{
189 		pSurface = myData.pDefaultMapSurface;
190 	}
191 	fZoomX = (double) myData.switcher.fOneViewportWidth / myData.iSurfaceWidth;  // both surfaces are loaded at the same size.
192 	fZoomY= (double) myData.switcher.fOneViewportHeight / myData.iSurfaceHeight;
193 
194 	// cadre exterieur.
195 	cairo_set_line_width (myDrawContext,myConfig.iLineSize);
196 	if (myConfig.bUseDefaultColors)
197 		gldi_style_colors_set_line_color (myDrawContext);
198 	else
199 		cairo_set_source_rgba(myDrawContext,myConfig.RGBLineColors[0],myConfig.RGBLineColors[1],myConfig.RGBLineColors[2],myConfig.RGBLineColors[3]);
200 	cairo_rectangle(myDrawContext,
201 		.5*myConfig.iLineSize,
202 		.5*myConfig.iLineSize,
203 		w - myConfig.iLineSize,
204 		h - myConfig.iLineSize);
205 
206 	cairo_stroke (myDrawContext);
207 
208 	// lignes interieures.
209 	cairo_set_line_width (myDrawContext,myConfig.iInLineSize);
210 	if (myConfig.bUseDefaultColors)
211 		gldi_style_colors_set_line_color (myDrawContext);
212 	else
213 		cairo_set_source_rgba (myDrawContext,myConfig.RGBInLineColors[0],myConfig.RGBInLineColors[1],myConfig.RGBInLineColors[2],myConfig.RGBInLineColors[3]);
214 	double xi, yj;
215 	int i, j;
216 	for (i = 1; i < myData.switcher.iNbColumns; i ++)  // lignes verticales.
217 	{
218 		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
219 		cairo_move_to (myDrawContext, xi, myConfig.iLineSize);
220 		cairo_rel_line_to (myDrawContext, 0, h - 2*myConfig.iLineSize);
221 		cairo_stroke (myDrawContext);
222 	}
223 	for (j = 1; j < myData.switcher.iNbLines; j ++)  // lignes horizontales.
224 	{
225 		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
226 		cairo_move_to (myDrawContext, myConfig.iLineSize, yj);
227 		cairo_rel_line_to (myDrawContext, w - 2*myConfig.iLineSize, 0);
228 		cairo_stroke (myDrawContext);
229 	}
230 
231 	GList *pWindowList = NULL;
232 	if (myConfig.bDrawWindows)
233 	{
234 		pWindowList = cairo_dock_get_current_applis_list ();
235 		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
236 	}
237 
238 	// chaque bureau/viewport.
239 	int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
240 	int k = 0, N = g_desktopGeometry.iNbDesktops * g_desktopGeometry.iNbViewportX * g_desktopGeometry.iNbViewportY;
241 	for (j = 0; j < myData.switcher.iNbLines && k < N; j ++)
242 	{
243 		for (i = 0; i < myData.switcher.iNbColumns && k < N; i ++)
244 		{
245 			cairo_save (myDrawContext);
246 
247 			xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
248 			yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);
249 
250 			cairo_translate (myDrawContext,
251 				xi,
252 				yj);
253 
254 			cairo_scale (myDrawContext,
255 				fZoomX,
256 				fZoomY);
257 			cairo_set_source_surface (myDrawContext,
258 				pSurface,
259 				0.,
260 				0.);
261 			cairo_paint(myDrawContext);
262 
263 			cairo_restore (myDrawContext);
264 
265 			if ((myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL_INVERTED && (i != myData.switcher.iCurrentColumn || j != myData.switcher.iCurrentLine))
266 			|| (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL && (i == myData.switcher.iCurrentColumn && j == myData.switcher.iCurrentLine)))
267 			{
268 				cairo_save (myDrawContext);
269 
270 				if (myConfig.bUseDefaultColors)
271 					gldi_style_colors_set_selected_bg_color (myDrawContext);
272 				else
273 					cairo_set_source_rgba (myDrawContext, myConfig.RGBIndColors[0], myConfig.RGBIndColors[1], myConfig.RGBIndColors[2], myConfig.RGBIndColors[3]);
274 				cairo_rectangle(myDrawContext,
275 					xi - .5*myConfig.iLineSize,
276 					yj - .5*myConfig.iLineSize,
277 					myData.switcher.fOneViewportWidth + myConfig.iLineSize,
278 					myData.switcher.fOneViewportHeight + myConfig.iLineSize);
279 				cairo_fill (myDrawContext);
280 
281 				cairo_restore (myDrawContext);
282 			}
283 
284 			if (myConfig.bDrawWindows)
285 			{
286 				cairo_save (myDrawContext);
287 
288 				cairo_translate (myDrawContext,
289 					xi,
290 					yj);
291 				cairo_set_line_width (myDrawContext, 1.);
292 				cairo_rectangle (myDrawContext,
293 					0.,
294 					0.,
295 					myData.switcher.fOneViewportWidth,
296 					myData.switcher.fOneViewportHeight);
297 				cairo_clip (myDrawContext);
298 
299 				//g_print (" dessin des fenetres du bureau (%d;%d;%d) ...\n", iNumDesktop, iNumViewportX, iNumViewportY);
300 				CDSwitcherDesktop data = {iNumDesktop, iNumViewportX, iNumViewportY, (int) myData.switcher.fOneViewportWidth, (int) myData.switcher.fOneViewportHeight, myDrawContext};
301 				g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, &data);
302 
303 				cairo_restore (myDrawContext);
304 			}
305 
306 			iNumViewportX ++;
307 			if (iNumViewportX == g_desktopGeometry.iNbViewportX)
308 			{
309 				iNumViewportX = 0;
310 				iNumViewportY ++;
311 				if (iNumViewportY == g_desktopGeometry.iNbViewportY)
312 				{
313 					iNumViewportY = 0;
314 					iNumDesktop ++;
315 				}
316 			}
317 			k ++;
318 		}
319 	}
320 
321 	// dessin de l'indicateur sur le bureau courant (on le fait maintenant car dans le cas ou la ligne interieure est plus petite que la ligne de l'indicateur, les surfaces suivantes recouvreraient en partie la ligne.
322 	if (myConfig.iDrawCurrentDesktopMode == SWICTHER_DRAW_FRAME)
323 	{
324 		i = myData.switcher.iCurrentColumn;
325 		j = myData.switcher.iCurrentLine;
326 		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
327 		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);
328 
329 		cairo_set_line_width (myDrawContext,myConfig.iLineSize);
330 		if (myConfig.bUseDefaultColors)
331 			gldi_style_colors_set_selected_bg_color (myDrawContext);
332 		else
333 			cairo_set_source_rgba (myDrawContext,myConfig.RGBIndColors[0],myConfig.RGBIndColors[1],myConfig.RGBIndColors[2],myConfig.RGBIndColors[3]);
334 		cairo_rectangle(myDrawContext,
335 			xi - .5*myConfig.iLineSize,
336 			yj - .5*myConfig.iLineSize,
337 			myData.switcher.fOneViewportWidth + myConfig.iLineSize,
338 			myData.switcher.fOneViewportHeight + myConfig.iLineSize);
339 
340 		if (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL)
341 			cairo_fill (myDrawContext);  // maybe we need to fill it with an alpha pattern in case we use the global style color ?...
342 		else
343 		{
344 			cairo_set_line_width (myDrawContext, MIN (4, 2*myConfig.iLineSize));
345 			cairo_stroke(myDrawContext);
346 		}
347 	}
348 
349 	cairo_restore (myDrawContext);
350 	g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
351 
352 	CD_APPLET_FINISH_DRAWING_MY_ICON_CAIRO;
353 }
354 
355 
cd_switcher_draw_main_icon_expanded_mode(void)356 void cd_switcher_draw_main_icon_expanded_mode (void)
357 {
358 	// apply the desktop bg or the user image on the main icon, in dock mode
359 	int iWidth, iHeight;
360 
361 	if (myDock)
362 	{
363 		CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
364 		myData.switcher.fOneViewportHeight = (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
365 		myData.switcher.fOneViewportWidth = (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.
366 
367 		cairo_surface_t *pSurface = NULL;
368 		double fZoomX, fZoomY;
369 		if (myConfig.iIconDrawing == SWICTHER_MAP_WALLPAPER)
370 		{
371 			cairo_dock_erase_cairo_context (myDrawContext);
372 
373 			pSurface = myData.pDesktopBgMapSurface;
374 			fZoomX = 1. * iWidth / myData.iSurfaceWidth;
375 			fZoomY= 1. * iHeight / myData.iSurfaceHeight;
376 			cairo_translate (myDrawContext,
377 				0.,
378 				0.);
379 
380 			cairo_save (myDrawContext);
381 			cairo_scale (myDrawContext,
382 				fZoomX ,
383 				fZoomY );
384 			cairo_set_source_surface (myDrawContext,
385 				pSurface,
386 				0.,
387 				0.);
388 			cairo_paint(myDrawContext);
389 			cairo_restore (myDrawContext);
390 
391 			if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
392 				cairo_dock_update_icon_texture (myIcon);
393 		}
394 		else
395 		{
396 			CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
397 		}
398 	}
399 
400 	if (myConfig.bDrawWindows)
401 	{
402 		GList *pWindowList = cairo_dock_get_current_applis_list ();
403 		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
404 
405 		CDSwitcherDesktop data;
406 		int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
407 		cairo_t *pCairoContext;
408 		Icon *pIcon;
409 		GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
410 		GList *ic;
411 		for (ic = pIconsList; ic != NULL; ic = ic->next)
412 		{
413 			pIcon = ic->data;
414 			cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
415 
416 			pCairoContext = cairo_create (pIcon->image.pSurface);
417 			cairo_set_line_width (pCairoContext, 1.);
418 			if (myConfig.bUseDefaultColors)
419 				gldi_style_colors_set_line_color (myDrawContext);
420 			else
421 				cairo_set_source_rgba (pCairoContext, myConfig.RGBWLineColors[0], myConfig.RGBWLineColors[1], myConfig.RGBWLineColors[2], myConfig.RGBWLineColors[3]);
422 
423 			data.iNumDesktop = iNumDesktop;
424 			data.iNumViewportX = iNumViewportX;
425 			data.iNumViewportY = iNumViewportY;
426 			data.iOneViewportWidth = iWidth;
427 			data.iOneViewportHeight = iHeight;
428 			data.pCairoContext = pCairoContext;
429 			g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, &data);
430 
431 			iNumViewportX ++;
432 			if (iNumViewportX == g_desktopGeometry.iNbViewportX)
433 			{
434 				iNumViewportY ++;
435 				if (iNumViewportY == g_desktopGeometry.iNbViewportY)
436 					iNumDesktop ++;
437 			}
438 			cairo_destroy (pCairoContext);
439 		}
440 		g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
441 	}
442 }
443 
444 /*Fonction de base pour toutes les autres*/
cd_switcher_draw_main_icon(void)445 void cd_switcher_draw_main_icon (void)
446 {
447 	cd_message ("%s (%d)", __func__, myConfig.bCompactView);
448 	if (myConfig.bCompactView)
449 	{
450 		cd_switcher_draw_main_icon_compact_mode ();
451 	}
452 	else
453 	{
454 		cd_switcher_draw_main_icon_expanded_mode ();
455 	}
456 
457 	CD_APPLET_REDRAW_MY_ICON;
458 }
459 
460 
cd_switcher_draw_desktops_bounding_box(CairoDesklet * pDesklet)461 void cd_switcher_draw_desktops_bounding_box (CairoDesklet *pDesklet)
462 {
463 	CD_APPLET_ENTER;
464 	//g_print ("%s (%.2Fx%.2f)\n", __func__, myData.switcher.fOneViewportWidth, myData.switcher.fOneViewportHeight);
465 	double x, y, w, h;
466 	glTranslatef (-pDesklet->container.iWidth/2, -pDesklet->container.iHeight/2, 0.);
467 
468 	w = myData.switcher.fOneViewportWidth/2;
469 	h = myData.switcher.fOneViewportHeight/2;
470 	int i, j;
471 	int k = 0, N = g_desktopGeometry.iNbDesktops * g_desktopGeometry.iNbViewportX * g_desktopGeometry.iNbViewportY;
472 
473 	for (j = 0; j < myData.switcher.iNbLines; j ++)  // lignes horizontales.
474 	{
475 		y = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
476 		y = pDesklet->container.iHeight - (y + h + myData.switcher.fOffsetY);
477 
478 		for (i = 0; i < myData.switcher.iNbColumns; i ++)  // lignes verticales.
479 		{
480 			x = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
481 			x += w + myData.switcher.fOffsetX;
482 
483 			glLoadName(i * myData.switcher.iNbLines + j + 1);  // +1 pour ne pas avoir 0.
484 
485 			glBegin(GL_QUADS);
486 			glVertex3f(x-w, y+h, 0.);
487 			glVertex3f(x+w, y+h, 0.);
488 			glVertex3f(x+w, y-h, 0.);
489 			glVertex3f(x-w, y-h, 0.);
490 			glEnd();
491 
492 			k ++;
493 			if (k == N)
494 				break;
495 		}
496 	}
497 	CD_APPLET_LEAVE ();
498 }
499 
cd_switcher_extract_viewport_coords_from_picked_object(CairoDesklet * pDesklet,int * iCoordX,int * iCoordY)500 void cd_switcher_extract_viewport_coords_from_picked_object (CairoDesklet *pDesklet, int *iCoordX, int *iCoordY)
501 {
502 	//g_print ("%s (%d)\n", __func__, pDesklet->iPickedObject);
503 	if (pDesklet->iPickedObject != 0)
504 	{
505 		pDesklet->iPickedObject --;  // cf le +1
506 		int i, j;
507 		i = pDesklet->iPickedObject / myData.switcher.iNbLines;
508 		j = pDesklet->iPickedObject % myData.switcher.iNbLines;
509 		//g_print ("bureau (%d;%d)\n", i, j);
510 
511 		double x, y, w, h;
512 		w = myData.switcher.fOneViewportWidth/2;
513 		h = myData.switcher.fOneViewportHeight/2;
514 		x = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
515 		x += w + myData.switcher.fOffsetX;
516 		y = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
517 		y += h + myData.switcher.fOffsetY;
518 		*iCoordX = x;
519 		*iCoordY = y;
520 	}
521 }
522 
523 
_show_window(GtkMenuItem * menu_item,Icon * pIcon)524 static void _show_window (GtkMenuItem *menu_item, Icon *pIcon)
525 {
526 	CD_APPLET_ENTER;
527 	gldi_window_show (pIcon->pAppli);
528 	CD_APPLET_LEAVE ();
529 }
530 
_show_desktop(GtkMenuItem * menu_item,gpointer data)531 static void _show_desktop (GtkMenuItem *menu_item, gpointer data)
532 {
533 	CD_APPLET_ENTER;
534 	int iIndex = GPOINTER_TO_INT (data);
535 	int iNumDesktop, iNumViewportX, iNumViewportY;
536 	cd_switcher_compute_desktop_from_index (iIndex, &iNumDesktop, &iNumViewportX, &iNumViewportY);
537 
538 	if (iNumViewportX != myData.switcher.iCurrentViewportX
539 	|| iNumViewportY != myData.switcher.iCurrentViewportY
540 	|| iNumDesktop != myData.switcher.iCurrentDesktop)
541 		gldi_desktop_set_current (iNumDesktop, iNumViewportX, iNumViewportY);
542 	CD_APPLET_LEAVE ();
543 }
_cd_switcher_add_window_on_viewport(Icon * pIcon,int iNumDesktop,int iNumViewportX,int iNumViewportY,GtkWidget * pMenu)544 static void _cd_switcher_add_window_on_viewport (Icon *pIcon, int iNumDesktop, int iNumViewportX, int iNumViewportY, GtkWidget *pMenu)
545 {
546 	//g_print (" + %s\n", pIcon->cName);
547 
548 	// on cree une copie de la surface de l'icone a la taille du menu.
549 	GdkPixbuf *pixbuf = cairo_dock_icon_buffer_to_pixbuf (pIcon);
550 	if (pixbuf == NULL)  // icon not loaded (because not in a dock, because inhibited)
551 	{
552 		const gchar *cIcon = cairo_dock_get_class_icon (pIcon->cClass);
553 		gint iDesiredIconSize = cairo_dock_search_icon_size (GTK_ICON_SIZE_LARGE_TOOLBAR); // 24px
554 		gchar *cIconPath = cairo_dock_search_icon_s_path (cIcon, iDesiredIconSize);
555 		if (cIconPath)
556 		{
557 			pixbuf = gdk_pixbuf_new_from_file_at_size (cIconPath,
558 				iDesiredIconSize,
559 				iDesiredIconSize,
560 				NULL);
561 		}
562 	}
563 
564 	// on ajoute une entree au menu avec le pixbuf.
565 	gchar *cLabel = cairo_dock_cut_string (pIcon->cName, 50);
566 	GtkWidget *pMenuItem = gldi_menu_add_item (pMenu, cLabel, "", G_CALLBACK (_show_window), pIcon);
567 	g_free (cLabel);
568 
569 	if (pixbuf)
570 	{
571 		GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
572 		gldi_menu_item_set_image (pMenuItem, image);
573 		g_object_unref (pixbuf);
574 	}
575 }
cd_switcher_build_windows_list(GtkWidget * pMenu)576 void cd_switcher_build_windows_list (GtkWidget *pMenu)
577 {
578 	GList *pWindowList = NULL;
579 	pWindowList = cairo_dock_get_current_applis_list ();
580 	pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
581 
582 	// chaque bureau/viewport.
583 	int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
584 	int k = 0, N = g_desktopGeometry.iNbDesktops * g_desktopGeometry.iNbViewportX * g_desktopGeometry.iNbViewportY;
585 	int iIndex = cd_switcher_compute_index_from_desktop (myData.switcher.iCurrentDesktop, myData.switcher.iCurrentViewportX, myData.switcher.iCurrentViewportY);
586 	GString *sDesktopName = g_string_new ("");
587 	int i, j;
588 	for (j = 0; j < myData.switcher.iNbLines; j ++)
589 	{
590 		for (i = 0; i < myData.switcher.iNbColumns; i ++)
591 		{
592 			// on ajoute le nom du bureau/viewport dans le menu.
593 			GtkWidget *pMenuItem = gtk_separator_menu_item_new ();
594 			gtk_menu_shell_append(GTK_MENU_SHELL (pMenu), pMenuItem);
595 			g_object_set (pMenuItem, "height-request", 3, NULL);
596 
597 			if (k < myData.iNbNames)
598 			{
599 				if (k == iIndex)
600 					g_string_printf (sDesktopName, "<b>%s (%s)</b>", myData.cDesktopNames[k], D_("Current"));
601 				else
602 					g_string_printf (sDesktopName, "<b>%s</b>", myData.cDesktopNames[k]);
603 			}
604 			else
605 			{
606 				if (k == iIndex)
607 					g_string_printf (sDesktopName, "<b>%s %d (%s)</b>", D_("Desktop"), k+1, D_("Current"));
608 				else
609 					g_string_printf (sDesktopName, "<b>%s %d</b>", D_("Desktop"), k+1);
610 			}
611 			pMenuItem = gldi_menu_add_item (pMenu, sDesktopName->str, NULL, G_CALLBACK (_show_desktop), GINT_TO_POINTER (k));
612 			GtkWidget *pLabel = gtk_bin_get_child (GTK_BIN(pMenuItem));
613 			gtk_label_set_use_markup (GTK_LABEL (pLabel), TRUE);
614 			gtk_misc_set_alignment (GTK_MISC (pLabel), .5, .5);
615 
616 			pMenuItem = gtk_separator_menu_item_new ();
617 			gtk_menu_shell_append(GTK_MENU_SHELL (pMenu), pMenuItem);
618 			g_object_set (pMenuItem, "height-request", 3, NULL);
619 
620 			// on ajoute les fenetres du viewport au menu.
621 			cd_debug ("Windows' listing (%d;%d;%d) ...", iNumDesktop, iNumViewportX, iNumViewportY);
622 			cd_switcher_foreach_window_on_viewport (iNumDesktop,
623 				iNumViewportX,
624 				iNumViewportY,
625 				(CDSwitcherActionOnViewportFunc) _cd_switcher_add_window_on_viewport,
626 				pMenu);
627 
628 			// on passe au viewport suivant.
629 			iNumViewportX ++;
630 			if (iNumViewportX == g_desktopGeometry.iNbViewportX)
631 			{
632 				iNumViewportX = 0;
633 				iNumViewportY ++;
634 				if (iNumViewportY == g_desktopGeometry.iNbViewportY)
635 				{
636 					iNumViewportY = 0;
637 					iNumDesktop ++;
638 				}
639 			}
640 			k ++;
641 			if (k == N)
642 				break ;
643 		}
644 	}
645 	g_string_free (sDesktopName, TRUE);
646 }
647 
648 
649 
_cd_switcher_move_window_to_viewport(Icon * pIcon,int iNumDesktop,int iNumViewportX,int iNumViewportY,gint * data)650 static void _cd_switcher_move_window_to_viewport (Icon *pIcon, int iNumDesktop, int iNumViewportX, int iNumViewportY, gint *data)
651 {
652 	int iDestNumDesktop = data[0];
653 	int iDestNumViewportX = data[1];
654 	int iDestNumViewportY = data[2];
655 
656 	gldi_window_move_to_desktop (pIcon->pAppli,
657 		iDestNumDesktop,
658 		(iDestNumViewportX - myData.switcher.iCurrentViewportX) * g_desktopGeometry.Xscreen.width,
659 		(iDestNumViewportY - myData.switcher.iCurrentViewportY) * g_desktopGeometry.Xscreen.height);
660 }
cd_switcher_move_current_desktop_to(int iNumDesktop,int iNumViewportX,int iNumViewportY)661 void cd_switcher_move_current_desktop_to (int iNumDesktop, int iNumViewportX, int iNumViewportY)
662 {
663 	gint data[3] = {iNumDesktop, iNumViewportX, iNumViewportY};
664 	cd_switcher_foreach_window_on_viewport (myData.switcher.iCurrentDesktop,
665 		myData.switcher.iCurrentViewportX,
666 		myData.switcher.iCurrentViewportY,
667 		(CDSwitcherActionOnViewportFunc) _cd_switcher_move_window_to_viewport,
668 		data);
669 }
670