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 <gtk/gtk.h>
22 
23 #include "cairo-dock-applications-manager.h"  // cairo_dock_set_icons_geometry_for_window_manager
24 #include "cairo-dock-launcher-manager.h"
25 #include "cairo-dock-separator-manager.h"  // GLDI_OBJECT_IS_SEPARATOR_ICON
26 #include "cairo-dock-stack-icon-manager.h"  // GLDI_OBJECT_IS_DRAWER_ICON
27 #include "cairo-dock-class-icon-manager.h"
28 #include "cairo-dock-icon-facility.h"
29 #include "cairo-dock-backends-manager.h"  // myBackendsParam.fSubDockSizeRatio
30 #include "cairo-dock-log.h"
31 #include "cairo-dock-style-manager.h"
32 #include "cairo-dock-dock-manager.h"
33 #include "cairo-dock-dialog-manager.h"  // gldi_dialogs_replace_all
34 #include "cairo-dock-indicator-manager.h"  // myIndicators.bUseClassIndic
35 #include "cairo-dock-animations.h"
36 #include "cairo-dock-desktop-manager.h"  // gldi_desktop_get*
37 #include "cairo-dock-data-renderer.h"  // cairo_dock_reload_data_renderer_on_icon
38 #include "cairo-dock-opengl.h"  // gldi_gl_container_begin_draw
39 
40 extern CairoDockGLConfig g_openglConfig;
41 #include "cairo-dock-dock-facility.h"
42 
43 extern gboolean g_bUseOpenGL;  // for cairo_dock_make_preview()
44 
45 
46 /**
47  * @pre iMaxIconHeight and fFlatDockWidth have to have been updated
48  */
cairo_dock_update_dock_size(CairoDock * pDock)49 void cairo_dock_update_dock_size (CairoDock *pDock)
50 {
51 	g_return_if_fail (pDock != NULL);
52 	//g_print ("%s (%p, %d)\n", __func__, pDock, pDock->iRefCount);
53 	if (pDock->iSidUpdateDockSize != 0)
54 	{
55 		//g_print (" -> delayed\n");
56 		return;
57 	}
58 	int iPrevMaxDockHeight = pDock->iMaxDockHeight;
59 	int iPrevMaxDockWidth = pDock->iMaxDockWidth;
60 
61 	//\__________________________ First compute the dock's size.
62 
63 	// set the icons' size back to their default, otherwise max_dock_size could be wrong
64 	if (pDock->container.fRatio != 0)
65 	{
66 		GList *ic;
67 		Icon *icon;
68 		pDock->fFlatDockWidth = -myIconsParam.iIconGap;
69 		pDock->iMaxIconHeight = 0;
70 		for (ic = pDock->icons; ic != NULL; ic = ic->next)
71 		{
72 			icon = ic->data;
73 			icon->fWidth /= pDock->container.fRatio;
74 			icon->fHeight /= pDock->container.fRatio;
75 			pDock->fFlatDockWidth += icon->fWidth + myIconsParam.iIconGap;
76 			if (! GLDI_OBJECT_IS_SEPARATOR_ICON (icon))
77 				pDock->iMaxIconHeight = MAX (pDock->iMaxIconHeight, icon->fHeight);
78 		}
79 		if (pDock->iMaxIconHeight == 0)
80 			pDock->iMaxIconHeight = 10;
81 		pDock->container.fRatio = 1.;
82 	}
83 
84 	// compute the size of the dock.
85 	pDock->iActiveWidth = pDock->iActiveHeight = 0;
86 	pDock->pRenderer->compute_size (pDock);
87 	if (pDock->iActiveWidth == 0)
88 		pDock->iActiveWidth = pDock->iMaxDockWidth;
89 	if (pDock->iActiveHeight == 0)
90 		pDock->iActiveHeight = pDock->iMaxDockHeight;
91 
92 	// in case it's larger than the screen, iterate on the ratio until it fits the screen's width
93 	int iScreenHeight = gldi_dock_get_screen_height (pDock);
94 	double hmax = pDock->iMaxIconHeight;
95 	int iMaxAuthorizedWidth = cairo_dock_get_max_authorized_dock_width (pDock);
96 	int n = 0;  // counter to ensure we'll not loop forever.
97 	do
98 	{
99 		double fPrevRatio = pDock->container.fRatio;
100 		//g_print ("  %s (%d / %d)\n", __func__, (int)pDock->iMaxDockWidth, iMaxAuthorizedWidth);
101 		if (pDock->iMaxDockWidth > iMaxAuthorizedWidth)
102 		{
103 			pDock->container.fRatio *= (double)iMaxAuthorizedWidth / pDock->iMaxDockWidth;
104 		}
105 		else
106 		{
107 			double fMaxRatio = (pDock->iRefCount == 0 ? 1 : myBackendsParam.fSubDockSizeRatio);
108 			if (pDock->container.fRatio < fMaxRatio)
109 			{
110 				pDock->container.fRatio *= (double)iMaxAuthorizedWidth / pDock->iMaxDockWidth;
111 				pDock->container.fRatio = MIN (pDock->container.fRatio, fMaxRatio);
112 			}
113 			else
114 				pDock->container.fRatio = fMaxRatio;
115 		}
116 
117 		if (pDock->iMaxDockHeight > iScreenHeight)
118 		{
119 			pDock->container.fRatio = MIN (pDock->container.fRatio, fPrevRatio * iScreenHeight / pDock->iMaxDockHeight);
120 		}
121 
122 		if (fPrevRatio != pDock->container.fRatio)
123 		{
124 			//g_print ("  -> change of the ratio : %.3f -> %.3f (%d, %d try)\n", fPrevRatio, pDock->container.fRatio, pDock->iRefCount, n);
125 			Icon *icon;
126 			GList *ic;
127 			pDock->fFlatDockWidth = -myIconsParam.iIconGap;
128 			for (ic = pDock->icons; ic != NULL; ic = ic->next)
129 			{
130 				icon = ic->data;
131 				icon->fWidth *= pDock->container.fRatio / fPrevRatio;
132 				icon->fHeight *= pDock->container.fRatio / fPrevRatio;
133 				pDock->fFlatDockWidth += icon->fWidth + myIconsParam.iIconGap;
134 			}
135 			hmax *= pDock->container.fRatio / fPrevRatio;
136 
137 			pDock->iActiveWidth = pDock->iActiveHeight = 0;
138 			pDock->pRenderer->compute_size (pDock);
139 			if (pDock->iActiveWidth == 0)
140 				pDock->iActiveWidth = pDock->iMaxDockWidth;
141 			if (pDock->iActiveHeight == 0)
142 				pDock->iActiveHeight = pDock->iMaxDockHeight;
143 		}
144 
145 		//g_print ("*** ratio : %.3f -> %.3f\n", fPrevRatio, pDock->container.fRatio);
146 		n ++;
147 	} while ((pDock->iMaxDockWidth > iMaxAuthorizedWidth || pDock->iMaxDockHeight > iScreenHeight || (pDock->container.fRatio < 1 && pDock->iMaxDockWidth < iMaxAuthorizedWidth-5)) && n < 8);
148 	pDock->iMaxIconHeight = hmax;
149 	//g_print (">>> iMaxIconHeight : %d, ratio : %.2f, fFlatDockWidth : %.2f\n", (int) pDock->iMaxIconHeight, pDock->container.fRatio, pDock->fFlatDockWidth);
150 
151 	//\__________________________ Then take the necessary actions due to the new size.
152 	// calculate the position of icons in the new frame.
153 	cairo_dock_calculate_dock_icons (pDock);
154 
155 	// update the dock's shape.
156 	if (iPrevMaxDockHeight == pDock->iMaxDockHeight && iPrevMaxDockWidth == pDock->iMaxDockWidth)  // if the size has changed, shapes will be updated by the "configure" callback, so we don't need to do it here; if not, we do it in case the icons define a new shape (ex.: separators in Panel view) or in case the screen edge has changed.
157 	{
158 		cairo_dock_update_input_shape (pDock);  // done after the icons' position is known.
159 		switch (pDock->iInputState)  // update the input zone
160 		{
161 			case CAIRO_DOCK_INPUT_ACTIVE: cairo_dock_set_input_shape_active (pDock); break;
162 			case CAIRO_DOCK_INPUT_AT_REST: cairo_dock_set_input_shape_at_rest (pDock); break;
163 			default: break;  // if hidden, nothing to do.
164 		}
165 	}
166 
167 	if (iPrevMaxDockHeight == pDock->iMaxDockHeight && iPrevMaxDockWidth == pDock->iMaxDockWidth)  // same remark as for the input shape.
168 	{
169 		/// TODO: check that...
170 		///pDock->bWMIconsNeedUpdate = TRUE;
171 		cairo_dock_trigger_set_WM_icons_geometry (pDock);
172 	}
173 
174 	// if the size has changed, move the dock to keep it centered.
175 	if (gldi_container_is_visible (CAIRO_CONTAINER (pDock)) && (iPrevMaxDockHeight != pDock->iMaxDockHeight || iPrevMaxDockWidth != pDock->iMaxDockWidth))
176 	{
177 		//g_print ("*******%s (%dx%d -> %dx%d)\n", __func__, iPrevMaxDockWidth, iPrevMaxDockHeight, pDock->iMaxDockWidth, pDock->iMaxDockHeight);
178 		cairo_dock_move_resize_dock (pDock);
179 	}
180 
181 	// reload its background.
182 	cairo_dock_trigger_load_dock_background (pDock);
183 
184 	// update the space reserved on the screen.
185 	if (pDock->iRefCount == 0 && pDock->iVisibility == CAIRO_DOCK_VISI_RESERVE)
186 		cairo_dock_reserve_space_for_dock (pDock, TRUE);
187 }
188 
_update_dock_size_idle(CairoDock * pDock)189 static gboolean _update_dock_size_idle (CairoDock *pDock)
190 {
191 	pDock->iSidUpdateDockSize = 0;
192 	cairo_dock_update_dock_size (pDock);
193 	gtk_widget_queue_draw (pDock->container.pWidget);
194 	return FALSE;
195 }
cairo_dock_trigger_update_dock_size(CairoDock * pDock)196 void cairo_dock_trigger_update_dock_size (CairoDock *pDock)
197 {
198 	if (pDock->iSidUpdateDockSize == 0)
199 	{
200 		pDock->iSidUpdateDockSize = g_idle_add ((GSourceFunc) _update_dock_size_idle, pDock);
201 	}
202 }
203 
_emit_leave_signal_delayed(CairoDock * pDock)204 static gboolean _emit_leave_signal_delayed (CairoDock *pDock)
205 {
206 	cairo_dock_emit_leave_signal (CAIRO_CONTAINER (pDock));
207 	pDock->iSidLeaveDemand = 0;
208 	return FALSE;
209 }
cairo_dock_manage_mouse_position(CairoDock * pDock)210 static void cairo_dock_manage_mouse_position (CairoDock *pDock)
211 {
212 	switch (pDock->iMousePositionType)
213 	{
214 		case CAIRO_DOCK_MOUSE_INSIDE :
215 			//g_print ("INSIDE (%d;%d;%d;%d;%d)\n", cairo_dock_entrance_is_allowed (pDock), pDock->iMagnitudeIndex, pDock->bIsGrowingUp, pDock->bIsShrinkingDown, pDock->iInputState);
216 			if (cairo_dock_entrance_is_allowed (pDock)
217 			    && ((pDock->iMagnitudeIndex < CAIRO_DOCK_NB_MAX_ITERATIONS
218 			         && ! pDock->bIsGrowingUp)
219 			       || pDock->bIsShrinkingDown)
220 			    && pDock->iInputState != CAIRO_DOCK_INPUT_HIDDEN
221 			    && (pDock->iInputState != CAIRO_DOCK_INPUT_AT_REST
222 			        || pDock->bIsDragging))
223 			        /* We are inside and icons' size is not the maximum even if
224 			         * the dock is not growing but we respect the 'cache' and
225 			         * 'idle' states
226 			         */
227 			{
228 				if (pDock->iRefCount != 0 && !pDock->container.bInside)
229 				{
230 
231 					break;
232 				}
233 				//pDock->container.bInside = TRUE;
234 				/* we do it not with 'auto-hide' mode because a entry signal is
235 				 * already sent due to the movements and resize of the window
236 				 * and we re-add it one here and it's a problem
237 				 * '! pDock->container.bInside' has been added to fix the bug
238 				 * when switching between desktops
239 				if ((pDock->bAtBottom && pDock->iRefCount == 0
240 				     && ! pDock->bAutoHide)
241 				   || (pDock->container.iWidth != pDock->iMaxDockWidth
242 				       || pDock->container.iHeight != pDock->iMaxDockHeight)
243 				   || ! pDock->container.bInside)
244 				 */
245 				if ((pDock->iMagnitudeIndex == 0 && pDock->iRefCount == 0
246 				     && ! pDock->bAutoHide && ! pDock->bIsGrowingUp)
247 				   || !pDock->container.bInside)
248 				   /* we are probably a little bit paranoia here, especially
249 				    * with the first case ... anyway, if we missed the
250 				    * 'enter' event for some reason, force it here.
251 				    */
252 				{
253 					//g_print ("  we emulate a re-entry (pDock->iMagnitudeIndex:%d)\n", pDock->iMagnitudeIndex);
254 					cairo_dock_emit_enter_signal (CAIRO_CONTAINER (pDock));
255 				}
256 				else // we settle for growing icons
257 				{
258 					//g_print ("  we settle for growing icons\n");
259 					cairo_dock_start_growing (pDock);
260 					if (pDock->bAutoHide && pDock->iRefCount == 0)
261 						cairo_dock_start_showing (pDock);
262 				}
263 			}
264 		break ;
265 
266 		case CAIRO_DOCK_MOUSE_ON_THE_EDGE :
267 			if (pDock->iMagnitudeIndex > 0 && ! pDock->bIsGrowingUp)
268 				cairo_dock_start_shrinking (pDock);
269 		break ;
270 
271 		case CAIRO_DOCK_MOUSE_OUTSIDE :
272 			//g_print ("en dehors du dock (bIsShrinkingDown:%d;bIsGrowingUp:%d;iMagnitudeIndex:%d)\n", pDock->bIsShrinkingDown, pDock->bIsGrowingUp, pDock->iMagnitudeIndex);
273 			if (! pDock->bIsGrowingUp && ! pDock->bIsShrinkingDown
274 			    && pDock->iSidLeaveDemand == 0 && pDock->iMagnitudeIndex > 0
275 			    && ! pDock->bIconIsFlyingAway)
276 			{
277 				if (pDock->iRefCount > 0)
278 				{
279 					Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pDock, NULL);
280 					if (pPointingIcon && pPointingIcon->bPointed)  // sous-dock pointe, on le laisse en position haute.
281 						return;
282 				}
283 				//g_print ("on force a quitter (iRefCount:%d; bIsGrowingUp:%d; iMagnitudeIndex:%d)\n", pDock->iRefCount, pDock->bIsGrowingUp, pDock->iMagnitudeIndex);
284 				pDock->iSidLeaveDemand = g_timeout_add (MAX (myDocksParam.iLeaveSubDockDelay, 300), (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pDock);
285 			}
286 		break ;
287 	}
288 }
cairo_dock_calculate_dock_icons(CairoDock * pDock)289 Icon *cairo_dock_calculate_dock_icons (CairoDock *pDock)
290 {
291 	Icon *pPointedIcon = pDock->pRenderer->calculate_icons (pDock);
292 	cairo_dock_manage_mouse_position (pDock);
293 	return pPointedIcon;
294 	/**if (pDock->iMousePositionType == CAIRO_DOCK_MOUSE_INSIDE)
295 	{
296 		return pPointedIcon;
297 	}
298 	else
299 	{
300 		if (pPointedIcon)
301 			pPointedIcon->bPointed = FALSE;
302 		return NULL;
303 	}*/
304 }
305 
306 
307 
308   ////////////////////////////////
309  /// WINDOW SIZE AND POSITION ///
310 ////////////////////////////////
311 
312 #define CANT_RESERVE_SPACE_WARNING "It's only possible to reserve space from the edge of the screen and not on the middle of two screens."
313 
314 #define _has_multiple_screens_and_on_one_screen(iNumScreen) (g_desktopGeometry.iNbScreens > 1 && iNumScreen > -1)
315 
cairo_dock_reserve_space_for_dock(CairoDock * pDock,gboolean bReserve)316 void cairo_dock_reserve_space_for_dock (CairoDock *pDock, gboolean bReserve)
317 {
318 	int left=0, right=0, top=0, bottom=0;
319 	int left_start_y=0, left_end_y=0, right_start_y=0, right_end_y=0, top_start_x=0, top_end_x=0, bottom_start_x=0, bottom_end_x=0;
320 
321 	if (bReserve)
322 	{
323 		int w = pDock->iMinDockWidth;
324 		int h = pDock->iMinDockHeight;
325 		int x, y;  // position that should have dock's window if it has a minimum size.
326 		cairo_dock_get_window_position_at_balance (pDock, w, h, &x, &y);
327 
328 		if (pDock->container.bDirectionUp)
329 		{
330 			if (pDock->container.bIsHorizontal)
331 			{
332 				if (_has_multiple_screens_and_on_one_screen (pDock->iNumScreen)
333 					&& cairo_dock_get_screen_position_y (pDock->iNumScreen) // y offset
334 						+ cairo_dock_get_screen_height (pDock->iNumScreen)  // height of the current screen
335 						< gldi_desktop_get_height ()) // total height
336 					cd_warning (CANT_RESERVE_SPACE_WARNING);
337 				else
338 				{
339 					bottom = h + pDock->iGapY;
340 					bottom_start_x = x;
341 					bottom_end_x = x + w;
342 				}
343 			}
344 			else
345 			{
346 				if (_has_multiple_screens_and_on_one_screen (pDock->iNumScreen)
347 					&& cairo_dock_get_screen_position_x (pDock->iNumScreen) // x offset
348 						+ cairo_dock_get_screen_width (pDock->iNumScreen)  // width of the current screen
349 						< gldi_desktop_get_width ()) // total width
350 					cd_warning (CANT_RESERVE_SPACE_WARNING);
351 				else
352 				{
353 					right = h + pDock->iGapY;
354 					right_start_y = x;
355 					right_end_y = x + w;
356 				}
357 			}
358 		}
359 		else
360 		{
361 			if (pDock->container.bIsHorizontal)
362 			{
363 				if (_has_multiple_screens_and_on_one_screen (pDock->iNumScreen)
364 					&& cairo_dock_get_screen_position_y (pDock->iNumScreen) > 0)
365 					cd_warning (CANT_RESERVE_SPACE_WARNING);
366 				else
367 				{
368 					top = h + pDock->iGapY;
369 					top_start_x = x;
370 					top_end_x = x + w;
371 				}
372 			}
373 			else
374 			{
375 				if (_has_multiple_screens_and_on_one_screen (pDock->iNumScreen)
376 					&& cairo_dock_get_screen_position_x (pDock->iNumScreen) > 0)
377 					cd_warning (CANT_RESERVE_SPACE_WARNING);
378 				else
379 				{
380 					left = h + pDock->iGapY;
381 					left_start_y = x;
382 					left_end_y = x + w;
383 				}
384 			}
385 		}
386 	}
387 	gldi_container_reserve_space (CAIRO_CONTAINER(pDock), left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x);
388 }
389 
cairo_dock_prevent_dock_from_out_of_screen(CairoDock * pDock)390 void cairo_dock_prevent_dock_from_out_of_screen (CairoDock *pDock)
391 {
392 	int x, y;  // position of the invariant point of the dock.
393 	x = pDock->container.iWindowPositionX +  pDock->container.iWidth * pDock->fAlign;
394 	y = (pDock->container.bDirectionUp ? pDock->container.iWindowPositionY + pDock->container.iHeight : pDock->container.iWindowPositionY);
395 	//cd_debug ("%s (%d;%d)", __func__, x, y);
396 
397 	int W = gldi_dock_get_screen_width (pDock), H = gldi_dock_get_screen_height (pDock);
398 	pDock->iGapX = x - W * pDock->fAlign;
399 	pDock->iGapY = (pDock->container.bDirectionUp ? H - y : y);
400 	//cd_debug (" -> (%d;%d)", pDock->iGapX, pDock->iGapY);
401 
402 	if (pDock->iGapX < - W/2)
403 		pDock->iGapX = - W/2;
404 	if (pDock->iGapX > W/2)
405 		pDock->iGapX = W/2;
406 	if (pDock->iGapY < 0)
407 		pDock->iGapY = 0;
408 	if (pDock->iGapY > H)
409 		pDock->iGapY = H;
410 }
411 
412 #define CD_VISIBILITY_MARGIN 20
cairo_dock_get_window_position_at_balance(CairoDock * pDock,int iNewWidth,int iNewHeight,int * iNewPositionX,int * iNewPositionY)413 void cairo_dock_get_window_position_at_balance (CairoDock *pDock, int iNewWidth, int iNewHeight, int *iNewPositionX, int *iNewPositionY)
414 {
415 	int W = gldi_dock_get_screen_width (pDock), H = gldi_dock_get_screen_height (pDock);
416 	int iWindowPositionX = (W - iNewWidth) * pDock->fAlign + pDock->iGapX;
417 	if (pDock->iRefCount == 0 && pDock->fAlign != .5)
418 		iWindowPositionX += (.5 - pDock->fAlign) * (pDock->iMaxDockWidth - iNewWidth);
419 	int iWindowPositionY = (pDock->container.bDirectionUp ? H - iNewHeight - pDock->iGapY : pDock->iGapY);
420 	//g_print ("pDock->iGapX : %d => iWindowPositionX <- %d\n", pDock->iGapX, iWindowPositionX);
421 	//g_print ("iNewHeight : %d -> pDock->container.iWindowPositionY <- %d\n", iNewHeight, iWindowPositionY);
422 
423 	if (pDock->iRefCount == 0)
424 	{
425 		if (iWindowPositionX + iNewWidth < CD_VISIBILITY_MARGIN)
426 			iWindowPositionX = CD_VISIBILITY_MARGIN - iNewWidth;
427 		else if (iWindowPositionX > W - CD_VISIBILITY_MARGIN)
428 			iWindowPositionX = W - CD_VISIBILITY_MARGIN;
429 	}
430 	else
431 	{
432 		if (iWindowPositionX < - pDock->iLeftMargin)
433 			iWindowPositionX = - pDock->iLeftMargin;
434 		else if (iWindowPositionX > W - iNewWidth + pDock->iMinRightMargin)
435 			iWindowPositionX = W - iNewWidth + pDock->iMinRightMargin;
436 	}
437 	if (iWindowPositionY < - pDock->iMaxIconHeight)
438 		iWindowPositionY = - pDock->iMaxIconHeight;
439 	else if (iWindowPositionY > H - iNewHeight + pDock->iMaxIconHeight)
440 		iWindowPositionY = H - iNewHeight + pDock->iMaxIconHeight;
441 
442 	*iNewPositionX = iWindowPositionX + gldi_dock_get_screen_offset_x (pDock);
443 	*iNewPositionY = iWindowPositionY + gldi_dock_get_screen_offset_y (pDock);
444 	//g_print ("POSITION : %d+%d ; %d+%d\n", iWindowPositionX, pDock->iScreenOffsetX, iWindowPositionY, pDock->iScreenOffsetY);
445 }
446 
_move_resize_dock(CairoDock * pDock)447 static gboolean _move_resize_dock (CairoDock *pDock)
448 {
449 	int iNewWidth = pDock->iMaxDockWidth;
450 	int iNewHeight = pDock->iMaxDockHeight;
451 	int iNewPositionX, iNewPositionY;
452 	cairo_dock_get_window_position_at_balance (pDock, iNewWidth, iNewHeight, &iNewPositionX, &iNewPositionY);
453 	/* We can't intercept the case where the new dimensions == current ones
454 	 * because we can have 2 resizes at the "same" time and they will cancel
455 	 * themselves (remove + insert of one icon). We need 2 configure otherwise
456 	 * the size will be blocked to the value of the first 'configure'
457 	 */
458 	//g_print (" -> %dx%d, %d;%d\n", iNewWidth, iNewHeight, iNewPositionX, iNewPositionY);
459 
460 	if (pDock->container.bIsHorizontal)
461 	{
462 		gdk_window_move_resize (gldi_container_get_gdk_window (CAIRO_CONTAINER (pDock)),
463 			iNewPositionX,
464 			iNewPositionY,
465 			iNewWidth,
466 			iNewHeight);
467 		/* When we have two gdk_window_move_resize in a row, Compiz will
468 		 * disturbed and it will block the draw of the dock. It seems Compiz
469 		 * sends too much 'configure' compare to Metacity.
470 		 */
471 	}
472 	else
473 	{
474 		gdk_window_move_resize (gldi_container_get_gdk_window (CAIRO_CONTAINER (pDock)),
475 			iNewPositionY,
476 			iNewPositionX,
477 			iNewHeight,
478 			iNewWidth);
479 	}
480 	pDock->iSidMoveResize = 0;
481 	return FALSE;
482 }
483 
cairo_dock_move_resize_dock(CairoDock * pDock)484 void cairo_dock_move_resize_dock (CairoDock *pDock)
485 {
486 	//g_print ("*********%s (current : %dx%d, %d;%d)\n", __func__, pDock->container.iWidth, pDock->container.iHeight, pDock->container.iWindowPositionX, pDock->container.iWindowPositionY);
487 	if (pDock->iSidMoveResize == 0)
488 	{
489 		pDock->iSidMoveResize = g_idle_add ((GSourceFunc)_move_resize_dock, pDock);
490 	}
491 	return ;
492 }
493 
494 
495   ///////////////////
496  /// INPUT SHAPE ///
497 ///////////////////
_cairo_dock_create_input_shape(CairoDock * pDock,int w,int h)498 static cairo_region_t *_cairo_dock_create_input_shape (CairoDock *pDock, int w, int h)
499 {
500  	int W = pDock->iMaxDockWidth;
501 	int H = pDock->iMaxDockHeight;
502 	if (W == 0 || H == 0)  // very unlikely to happen, but anyway avoid this case.
503 	{
504 		return NULL;
505 	}
506 
507 	double offset = (W - pDock->iActiveWidth) * pDock->fAlign + (pDock->iActiveWidth - w) / 2;
508 
509 	cairo_region_t *pShapeBitmap;
510 	if (pDock->container.bIsHorizontal)
511 	{
512 		pShapeBitmap = gldi_container_create_input_shape (CAIRO_CONTAINER (pDock),
513 			///(W - w) * pDock->fAlign,
514 			offset,
515 			pDock->container.bDirectionUp ? H - h : 0,
516 			w,
517 			h);
518 	}
519 	else
520 	{
521 		pShapeBitmap = gldi_container_create_input_shape (CAIRO_CONTAINER (pDock),
522 			pDock->container.bDirectionUp ? H - h : 0,
523 			///(W - w) * pDock->fAlign,
524 			offset,
525 			h,
526 			w);
527 	}
528 	return pShapeBitmap;
529 }
530 
cairo_dock_update_input_shape(CairoDock * pDock)531 void cairo_dock_update_input_shape (CairoDock *pDock)
532 {
533 	//\_______________ destroy the current input zones.
534 	if (pDock->pShapeBitmap != NULL)
535 	{
536 		cairo_region_destroy (pDock->pShapeBitmap);
537 		pDock->pShapeBitmap = NULL;
538 	}
539 	if (pDock->pHiddenShapeBitmap != NULL)
540 	{
541 		cairo_region_destroy (pDock->pHiddenShapeBitmap);
542 		pDock->pHiddenShapeBitmap = NULL;
543 	}
544 	if (pDock->pActiveShapeBitmap != NULL)
545 	{
546 		cairo_region_destroy (pDock->pActiveShapeBitmap);
547 		pDock->pActiveShapeBitmap = NULL;
548 	}
549 
550 	//\_______________ define the input zones' geometry
551 	int W = pDock->iMaxDockWidth;
552 	int H = pDock->iMaxDockHeight;
553 	int w = pDock->iMinDockWidth;
554 	int h = pDock->iMinDockHeight;
555 	//g_print ("%s (%dx%d; %dx%d)\n", __func__, w, h, W, H);
556 	int w_ = 0;  // Note: in older versions of X, a fully empty input shape was not working and we had to set 1 pixel ON.
557 	int h_ = 0;
558 
559 	//\_______________ check that the dock can have input zones.
560 	if (w == 0 || h == 0 || pDock->iRefCount > 0 || W == 0 || H == 0)
561 	{
562 		if (pDock->iActiveWidth != pDock->iMaxDockWidth || pDock->iActiveHeight != pDock->iMaxDockHeight)
563 			// else all the dock is active when the mouse is inside, so we can just set a NULL shape.
564 			pDock->pActiveShapeBitmap = _cairo_dock_create_input_shape (pDock, pDock->iActiveWidth, pDock->iActiveHeight);
565 		if (pDock->iInputState != CAIRO_DOCK_INPUT_ACTIVE)
566 		{
567 			//g_print ("+++ input shape active on update input shape\n");
568 			cairo_dock_set_input_shape_active (pDock);
569 			pDock->iInputState = CAIRO_DOCK_INPUT_ACTIVE;
570 		}
571 		return ;
572 	}
573 
574 	//\_______________ create the input zones based on the previous geometries.
575 	pDock->pShapeBitmap = _cairo_dock_create_input_shape (pDock, w, h);
576 
577 	pDock->pHiddenShapeBitmap = _cairo_dock_create_input_shape (pDock, w_, h_);
578 
579 	if (pDock->iActiveWidth != pDock->iMaxDockWidth || pDock->iActiveHeight != pDock->iMaxDockHeight)
580 		// else all the dock is active when the mouse is inside, so we can just set a NULL shape.
581 		pDock->pActiveShapeBitmap = _cairo_dock_create_input_shape (pDock, pDock->iActiveWidth, pDock->iActiveHeight);
582 
583 	//\_______________ if the renderer can define the input shape, let it finish the job.
584 	if (pDock->pRenderer->update_input_shape != NULL)
585 		pDock->pRenderer->update_input_shape (pDock);
586 }
587 
588 
589 
590   ///////////////////
591  /// LINEAR DOCK ///
592 ///////////////////
593 
cairo_dock_calculate_icons_positions_at_rest_linear(GList * pIconList,double fFlatDockWidth)594 void cairo_dock_calculate_icons_positions_at_rest_linear (GList *pIconList, double fFlatDockWidth)
595 {
596 	//g_print ("%s (%d, +%d)\n", __func__, fFlatDockWidth);
597 	double x_cumulated = 0;
598 	GList* ic;
599 	Icon *icon;
600 	for (ic = pIconList; ic != NULL; ic = ic->next)
601 	{
602 		icon = ic->data;
603 
604 		if (x_cumulated + icon->fWidth / 2 < 0)
605 			icon->fXAtRest = x_cumulated + fFlatDockWidth;
606 		else if (x_cumulated + icon->fWidth / 2 > fFlatDockWidth)
607 			icon->fXAtRest = x_cumulated - fFlatDockWidth;
608 		else
609 			icon->fXAtRest = x_cumulated;
610 		//g_print ("%s : fXAtRest = %.2f\n", icon->cName, icon->fXAtRest);
611 
612 		x_cumulated += icon->fWidth + myIconsParam.iIconGap;
613 	}
614 }
615 
cairo_dock_calculate_max_dock_width(CairoDock * pDock,double fFlatDockWidth,double fWidthConstraintFactor,double fExtraWidth)616 double cairo_dock_calculate_max_dock_width (CairoDock *pDock, double fFlatDockWidth, double fWidthConstraintFactor, double fExtraWidth)
617 {
618 	double fMaxDockWidth = 0.;
619 	//g_print ("%s (%d)\n", __func__, (int)fFlatDockWidth);
620 	GList *pIconList = pDock->icons;
621 	if (pIconList == NULL)
622 		return 2 * myDocksParam.iDockRadius + myDocksParam.iDockLineWidth + 2 * myDocksParam.iFrameMargin;
623 
624 	// We reset extreme positions of the icons.
625 	GList* ic;
626 	Icon *icon;
627 	for (ic = pIconList; ic != NULL; ic = ic->next)
628 	{
629 		icon = ic->data;
630 		icon->fXMax = -1e4;
631 		icon->fXMin = 1e4;
632 	}
633 
634 	/* We simulate the move of the cursor in all the width of the dock and we
635 	 * get the maximum width and the balance position for each icon.
636 	 */
637 	GList *ic2;
638 	for (ic = pIconList; ic != NULL; ic = ic->next)
639 	{
640 		icon = ic->data;
641 
642 		cairo_dock_calculate_wave_with_position_linear (pIconList, icon->fXAtRest, pDock->fMagnitudeMax, fFlatDockWidth, 0, 0, 0.5, 0, pDock->container.bDirectionUp);
643 
644 		for (ic2 = pIconList; ic2 != NULL; ic2 = ic2->next)
645 		{
646 			icon = ic2->data;
647 
648 			if (icon->fX + icon->fWidth * icon->fScale > icon->fXMax)
649 				icon->fXMax = icon->fX + icon->fWidth * icon->fScale;
650 			if (icon->fX < icon->fXMin)
651 				icon->fXMin = icon->fX;
652 		}
653 	}
654 	cairo_dock_calculate_wave_with_position_linear (pIconList, fFlatDockWidth - 1, pDock->fMagnitudeMax, fFlatDockWidth, 0, 0, pDock->fAlign, 0, pDock->container.bDirectionUp);  // last calculation at the extreme right of the dock.
655 	for (ic = pIconList; ic != NULL; ic = ic->next)
656 	{
657 		icon = ic->data;
658 
659 		if (icon->fX + icon->fWidth * icon->fScale > icon->fXMax)
660 			icon->fXMax = icon->fX + icon->fWidth * icon->fScale;
661 		if (icon->fX < icon->fXMin)
662 			icon->fXMin = icon->fX;
663 	}
664 
665 	fMaxDockWidth = (icon->fXMax - ((Icon *) pIconList->data)->fXMin) * fWidthConstraintFactor + fExtraWidth;
666 	fMaxDockWidth = ceil (fMaxDockWidth) + 1;
667 
668 	for (ic = pIconList; ic != NULL; ic = ic->next)
669 	{
670 		icon = ic->data;
671 		icon->fXMin += fMaxDockWidth / 2;
672 		icon->fXMax += fMaxDockWidth / 2;
673 		//g_print ("%s : [%d;%d]\n", icon->cName, (int) icon->fXMin, (int) icon->fXMax);
674 		icon->fX = icon->fXAtRest;
675 		icon->fScale = 1;
676 	}
677 
678 	return fMaxDockWidth;
679 }
680 
cairo_dock_calculate_wave_with_position_linear(GList * pIconList,int x_abs,gdouble fMagnitude,double fFlatDockWidth,int iWidth,int iHeight,double fAlign,double fFoldingFactor,gboolean bDirectionUp)681 Icon * cairo_dock_calculate_wave_with_position_linear (GList *pIconList, int x_abs, gdouble fMagnitude, double fFlatDockWidth, int iWidth, int iHeight, double fAlign, double fFoldingFactor, gboolean bDirectionUp)
682 {
683 	//g_print (">>>>>%s (%d/%.2f, %dx%d, %.2f, %.2f)\n", __func__, x_abs, fFlatDockWidth, iWidth, iHeight, fAlign, fFoldingFactor);
684 	if (pIconList == NULL)
685 		return NULL;
686 	if (x_abs < 0 && iWidth > 0)
687 		// to avoid too quick resize when leaving from the edges.
688 		///x_abs = -1;
689 		x_abs = 0;
690 	else if (x_abs > fFlatDockWidth && iWidth > 0)
691 		///x_abs = fFlatDockWidth+1;
692 		x_abs = (int) fFlatDockWidth;
693 
694 
695 	float x_cumulated = 0, fXMiddle, fDeltaExtremum;
696 	GList* ic, *pointed_ic;
697 	Icon *icon, *prev_icon;
698 	double fScale = 0.;
699 	double offset = 0.;
700 	pointed_ic = (x_abs < 0 ? pIconList : NULL);
701 	for (ic = pIconList; ic != NULL; ic = ic->next)
702 	{
703 		icon = ic->data;
704 		x_cumulated = icon->fXAtRest;
705 		fXMiddle = icon->fXAtRest + icon->fWidth / 2;
706 
707 		//\_______________ We compute its phase (pi/2 next to the cursor).
708 		icon->fPhase = (fXMiddle - x_abs) / myIconsParam.iSinusoidWidth * G_PI + G_PI / 2;
709 		if (icon->fPhase < 0)
710 		{
711 			icon->fPhase = 0;
712 		}
713 		else if (icon->fPhase > G_PI)
714 		{
715 			icon->fPhase = G_PI;
716 		}
717 
718 		//\_______________ We deduct the sinusoidal amplitude next to the icon (its scale)
719 		icon->fScale = 1 + fMagnitude * myIconsParam.fAmplitude * sin (icon->fPhase);
720 		if (iWidth > 0 && icon->fInsertRemoveFactor != 0)
721 		{
722 			fScale = icon->fScale;
723 			///offset += (icon->fWidth * icon->fScale) * (pointed_ic == NULL ? 1 : -1);
724 			if (icon->fInsertRemoveFactor > 0)
725 				icon->fScale *= icon->fInsertRemoveFactor;
726 			else
727 				icon->fScale *= (1 + icon->fInsertRemoveFactor);
728 			///offset -= (icon->fWidth * icon->fScale) * (pointed_ic == NULL ? 1 : -1);
729 		}
730 
731 		icon->fY = (bDirectionUp ? iHeight - myDocksParam.iDockLineWidth - myDocksParam.iFrameMargin - icon->fScale * icon->fHeight : myDocksParam.iDockLineWidth + myDocksParam.iFrameMargin);
732 		//g_print ("%s fY : %d; %.2f\n", icon->cName, iHeight, icon->fHeight);
733 
734 		/* If we already have defined a pointed icon, we can move the current
735 		 * icon compared to the previous one
736 		 */
737 		if (pointed_ic != NULL)
738 		{
739 			if (ic == pIconList)  // can happen if we are outside from the left of the dock.
740 			{
741 				icon->fX = x_cumulated - 1. * (fFlatDockWidth - iWidth) / 2;
742 				//g_print ("  outside from the left : icon->fX = %.2f (%.2f)\n", icon->fX, x_cumulated);
743 			}
744 			else
745 			{
746 				prev_icon = (ic->prev != NULL ? ic->prev->data : cairo_dock_get_last_icon (pIconList));
747 				icon->fX = prev_icon->fX + (prev_icon->fWidth + myIconsParam.iIconGap) * prev_icon->fScale;
748 
749 				if (icon->fX + icon->fWidth * icon->fScale > icon->fXMax - myIconsParam.fAmplitude * fMagnitude * (icon->fWidth + 1.5*myIconsParam.iIconGap) / 8 && iWidth != 0)
750 				{
751 					//g_print ("  we constraint %s (fXMax=%.2f , fX=%.2f\n", prev_icon->cName, prev_icon->fXMax, prev_icon->fX);
752 					fDeltaExtremum = icon->fX + icon->fWidth * icon->fScale - (icon->fXMax - myIconsParam.fAmplitude * fMagnitude * (icon->fWidth + 1.5*myIconsParam.iIconGap) / 16);
753 					if (myIconsParam.fAmplitude != 0)
754 						icon->fX -= fDeltaExtremum * (1 - (icon->fScale - 1) / myIconsParam.fAmplitude) * fMagnitude;
755 				}
756 			}
757 			icon->fX = fAlign * iWidth + (icon->fX - fAlign * iWidth) * (1. - fFoldingFactor);
758 			//g_print ("  on the right : icon->fX = %.2f (%.2f)\n", icon->fX, x_cumulated);
759 		}
760 
761 		//\_______________ We check if we have a pointer on this icon.
762 		if (pointed_ic == NULL
763 		    && x_cumulated + icon->fWidth + .5*myIconsParam.iIconGap >= x_abs
764 		    && x_cumulated - .5*myIconsParam.iIconGap <= x_abs) // we found the pointed icon.
765 		{
766 			pointed_ic = ic;
767 			///icon->bPointed = TRUE;
768 			icon->bPointed = (x_abs != (int) fFlatDockWidth && x_abs != 0);
769 			icon->fX = x_cumulated - (fFlatDockWidth - iWidth) / 2 + (1 - icon->fScale) * (x_abs - x_cumulated + .5*myIconsParam.iIconGap);
770 			icon->fX = fAlign * iWidth + (icon->fX - fAlign * iWidth) * (1. - fFoldingFactor);
771 			//g_print ("  pointed icon: fX = %.2f (%.2f, %d)\n", icon->fX, x_cumulated, icon->bPointed);
772 		}
773 		else
774 			icon->bPointed = FALSE;
775 
776 		if (iWidth > 0 && icon->fInsertRemoveFactor != 0)
777 		{
778 			if (pointed_ic != ic)  // bPointed can be false for the last icon on the right.
779 				offset += (icon->fWidth * (fScale - icon->fScale)) * (pointed_ic == NULL ? 1 : -1);
780 			else
781 				offset += (2*(fXMiddle - x_abs) * (fScale - icon->fScale)) * (pointed_ic == NULL ? 1 : -1);
782 		}
783 	}
784 
785 	//\_______________ We place icons before pointed icon beside this one
786 	if (pointed_ic == NULL)  // We are at the right of icons.
787 	{
788 		pointed_ic = g_list_last (pIconList);
789 		icon = pointed_ic->data;
790 		icon->fX = x_cumulated - (fFlatDockWidth - iWidth) / 2 + (1 - icon->fScale) * (icon->fWidth + .5*myIconsParam.iIconGap);
791 		icon->fX = fAlign * iWidth + (icon->fX - fAlign * iWidth) * (1 - fFoldingFactor);
792 		//g_print ("  outside on the right: icon->fX = %.2f (%.2f)\n", icon->fX, x_cumulated);
793 	}
794 
795 	ic = pointed_ic;
796 	while (ic != pIconList)
797 	{
798 		icon = ic->data;
799 
800 		ic = ic->prev;  // since ic != pIconList, ic->prev is not NULL
801 		prev_icon = ic->data;
802 
803 		prev_icon->fX = icon->fX - (prev_icon->fWidth + myIconsParam.iIconGap) * prev_icon->fScale;
804 		//g_print ("fX <- %.2f; fXMin : %.2f\n", prev_icon->fX, prev_icon->fXMin);
805 		if (prev_icon->fX < prev_icon->fXMin + myIconsParam.fAmplitude * fMagnitude * (prev_icon->fWidth + 1.5*myIconsParam.iIconGap) / 8
806 		    && iWidth != 0 && x_abs < iWidth && fMagnitude > 0)  /// && prev_icon->fPhase == 0
807 		    // We re-add 'fMagnitude > 0' otherwise we have a small jump due to constraints on the left of the pointed icon.
808 		{
809 			//g_print ("  we constraint %s (fXMin=%.2f , fX=%.2f\n", prev_icon->cName, prev_icon->fXMin, prev_icon->fX);
810 			fDeltaExtremum = prev_icon->fX - (prev_icon->fXMin + myIconsParam.fAmplitude * fMagnitude * (prev_icon->fWidth + 1.5*myIconsParam.iIconGap) / 16);
811 			if (myIconsParam.fAmplitude != 0)
812 				prev_icon->fX -= fDeltaExtremum * (1 - (prev_icon->fScale - 1) / myIconsParam.fAmplitude) * fMagnitude;
813 		}
814 		prev_icon->fX = fAlign * iWidth + (prev_icon->fX - fAlign * iWidth) * (1. - fFoldingFactor);
815 		//g_print ("  prev_icon->fX : %.2f\n", prev_icon->fX);
816 	}
817 
818 	if (offset != 0)
819 	{
820 		offset /= 2;
821 		//g_print ("offset : %.2f (pointed:%s)\n", offset, pointed_ic?((Icon*)pointed_ic->data)->cName:"none");
822 		for (ic = pIconList; ic != NULL; ic = ic->next)
823 		{
824 			icon = ic->data;
825 			//if (ic == pIconList)
826 			//	cd_debug ("fX : %.2f - %.2f", icon->fX, offset);
827 			icon->fX -= offset;
828 		}
829 	}
830 
831 	icon = pointed_ic->data;
832 	return (icon->bPointed ? icon : NULL);
833 }
834 
cairo_dock_apply_wave_effect_linear(CairoDock * pDock)835 Icon *cairo_dock_apply_wave_effect_linear (CairoDock *pDock)
836 {
837 	//\_______________ We compute the cursor's position in the container of the flat dock
838 	//int dx = pDock->container.iMouseX - (pDock->iOffsetForExtend * (pDock->fAlign - .5) * 2) - pDock->container.iWidth / 2;  // gap compare to the middle of the flat dock.
839 	//int x_abs = dx + pDock->fFlatDockWidth / 2;  // gap compare to the left of the minimal flat dock.
840 	//g_print ("%s (flat:%d, w:%d, x:%d)\n", __func__, (int)pDock->fFlatDockWidth, pDock->container.iWidth, pDock->container.iMouseX);
841 	double offset = (pDock->container.iWidth - pDock->iActiveWidth) * pDock->fAlign + (pDock->iActiveWidth - pDock->fFlatDockWidth) / 2;
842 	int x_abs = pDock->container.iMouseX - offset;
843 
844 	//\_______________ We compute all parameters for the icons.
845 	double fMagnitude = cairo_dock_calculate_magnitude (pDock->iMagnitudeIndex);  // * pDock->fMagnitudeMax
846 	Icon *pPointedIcon = cairo_dock_calculate_wave_with_position_linear (pDock->icons, x_abs, fMagnitude, pDock->fFlatDockWidth, pDock->container.iWidth, pDock->container.iHeight, pDock->fAlign, pDock->fFoldingFactor, pDock->container.bDirectionUp);  // iMaxDockWidth
847 	return pPointedIcon;
848 }
849 
cairo_dock_get_current_dock_width_linear(CairoDock * pDock)850 double cairo_dock_get_current_dock_width_linear (CairoDock *pDock)
851 {
852 	if (pDock->icons == NULL)
853 		//return 2 * myDocksParam.iDockRadius + myDocksParam.iDockLineWidth + 2 * myDocksParam.iFrameMargin;
854 		return 1 + 2 * myDocksParam.iFrameMargin;
855 
856 	Icon *pLastIcon = cairo_dock_get_last_icon (pDock->icons);
857 	Icon *pFirstIcon = cairo_dock_get_first_icon (pDock->icons);
858 	double fWidth = pLastIcon->fX - pFirstIcon->fX + pLastIcon->fWidth * pLastIcon->fScale + 2 * myDocksParam.iFrameMargin;  //  + 2 * myDocksParam.iDockRadius + myDocksParam.iDockLineWidth + 2 * myDocksParam.iFrameMargin
859 
860 	return fWidth;
861 }
862 
cairo_dock_check_if_mouse_inside_linear(CairoDock * pDock)863 void cairo_dock_check_if_mouse_inside_linear (CairoDock *pDock)
864 {
865 	CairoDockMousePositionType iMousePositionType;
866 	int iWidth = pDock->container.iWidth;
867 	///int iHeight = (pDock->fMagnitudeMax != 0 ? pDock->container.iHeight : pDock->iMinDockHeight);
868 	int iHeight = pDock->iActiveHeight;
869 	///int iExtraHeight = (pDock->bAtBottom ? 0 : myIconsParam.iLabelSize);
870 	// int iExtraHeight = 0;  /// we should check if we have a sub-dock or a dialogue on top of it :-/
871 	int iMouseX = pDock->container.iMouseX;
872 	int iMouseY = (pDock->container.bDirectionUp ? pDock->container.iHeight - pDock->container.iMouseY : pDock->container.iMouseY);
873 	//g_print ("%s (%dx%d, %dx%d, %f)\n", __func__, iMouseX, iMouseY, iWidth, iHeight, pDock->fFoldingFactor);
874 
875 	//\_______________ We check if the cursor is in the dock and we change icons size according to that.
876 	double offset = (iWidth - pDock->iActiveWidth) * pDock->fAlign + (pDock->iActiveWidth - pDock->fFlatDockWidth) / 2;
877 	int x_abs = pDock->container.iMouseX - offset;
878 	///int x_abs = pDock->container.iMouseX + (pDock->fFlatDockWidth - iWidth) * pDock->fAlign;  // abscisse par rapport a la gauche du dock minimal plat.
879 	gboolean bMouseInsideDock = (x_abs >= 0 && x_abs <= pDock->fFlatDockWidth && iMouseX > 0 && iMouseX < iWidth);
880 	//g_print ("bMouseInsideDock : %d (%d;%d/%.2f)\n", bMouseInsideDock, pDock->container.bInside, x_abs, pDock->fFlatDockWidth);
881 
882 	if (iMouseY >= 0 && iMouseY < iHeight) { // inside in the Y axis
883 		if (! bMouseInsideDock)  // outside of the dock but on the edge.
884 			iMousePositionType = CAIRO_DOCK_MOUSE_ON_THE_EDGE;
885 		else
886 			iMousePositionType = CAIRO_DOCK_MOUSE_INSIDE;
887 	}
888 	else
889 		iMousePositionType = CAIRO_DOCK_MOUSE_OUTSIDE;
890 
891 	pDock->iMousePositionType = iMousePositionType;
892 }
893 
894 
895 #define make_icon_avoid_mouse(icon, sens) do { \
896 	cairo_dock_mark_icon_as_avoiding_mouse (icon);\
897 	icon->fAlpha = 0.75;\
898 	if (myIconsParam.fAmplitude != 0)\
899 		icon->fDrawX += icon->fWidth * icon->fScale / 4 * sens; } while (0)
_cairo_dock_check_can_drop_linear(CairoDock * pDock,CairoDockIconGroup iGroup,double fMargin)900 static inline gboolean _cairo_dock_check_can_drop_linear (CairoDock *pDock, CairoDockIconGroup iGroup, double fMargin)
901 {
902 	gboolean bCanDrop = FALSE;
903 	Icon *icon;
904 	GList *ic;
905 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
906 	{
907 		icon = ic->data;
908 		if (icon->bPointed)
909 		{
910 			cd_debug ("icon->fWidth: %d, %.2f", (int)icon->fWidth, icon->fScale);
911 			cd_debug ("x: %d / %d", pDock->container.iMouseX, (int)icon->fDrawX);
912 			if (pDock->container.iMouseX < icon->fDrawX + icon->fWidth * icon->fScale * fMargin)  // we are on the left.  // fDrawXAtRest
913 			{
914 				Icon *prev_icon = (ic->prev ? ic->prev->data : NULL);
915 				if (icon->iGroup == iGroup || (prev_icon && prev_icon->iGroup == iGroup))
916 				{
917 					make_icon_avoid_mouse (icon, 1);
918 					if (prev_icon)
919 						make_icon_avoid_mouse (prev_icon, -1);
920 					//g_print ("%s> <%s\n", prev_icon->cName, icon->cName);
921 					bCanDrop = TRUE;
922 				}
923 			}
924 			else if (pDock->container.iMouseX > icon->fDrawX + icon->fWidth * icon->fScale * (1 - fMargin))  // on est a droite.  // fDrawXAtRest
925 			{
926 				Icon *next_icon = (ic->next ? ic->next->data : NULL);
927 				if (icon->iGroup == iGroup || (next_icon && next_icon->iGroup == iGroup))
928 				{
929 					make_icon_avoid_mouse (icon, -1);
930 					if (next_icon)
931 						make_icon_avoid_mouse (next_icon, 1);
932 					//g_print ("%s> <%s\n", icon->cName, next_icon->cName);
933 					bCanDrop = TRUE;
934 				}
935 				ic = ic->next;  // we skip it.
936 				if (ic == NULL)
937 					break;
938 			}  // else: we are on top of it.
939 		}
940 		else
941 			cairo_dock_stop_marking_icon_as_avoiding_mouse (icon);
942 	}
943 
944 	return bCanDrop;
945 }
946 
947 
cairo_dock_check_can_drop_linear(CairoDock * pDock)948 void cairo_dock_check_can_drop_linear (CairoDock *pDock)
949 {
950 	if (! pDock->bIsDragging)  // not dragging, so no drop possible.
951 	{
952 		pDock->bCanDrop = FALSE;
953 	}
954 	else if (pDock->icons == NULL)  // dragging but no icons, so drop always possible.
955 	{
956 		pDock->bCanDrop = TRUE;
957 	}
958 	else  // dragging and some icons.
959 	{
960 		pDock->bCanDrop = _cairo_dock_check_can_drop_linear (pDock, pDock->iAvoidingMouseIconType, pDock->fAvoidingMouseMargin);
961 	}
962 }
963 
cairo_dock_stop_marking_icons(CairoDock * pDock)964 void cairo_dock_stop_marking_icons (CairoDock *pDock)
965 {
966 	if (pDock->icons == NULL)
967 		return;
968 	//g_print ("%s (%d)\n", __func__, iType);
969 
970 	Icon *icon;
971 	GList *ic;
972 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
973 	{
974 		icon = ic->data;
975 		cairo_dock_stop_marking_icon_as_avoiding_mouse (icon);
976 	}
977 }
978 
979 
cairo_dock_set_subdock_position_linear(Icon * pPointedIcon,CairoDock * pDock)980 void cairo_dock_set_subdock_position_linear (Icon *pPointedIcon, CairoDock *pDock)
981 {
982 	CairoDock *pSubDock = pPointedIcon->pSubDock;
983 	///int iX = pPointedIcon->fXAtRest - (pDock->fFlatDockWidth - pDock->iMaxDockWidth) / 2 + pPointedIcon->fWidth / 2 + (pDock->iOffsetForExtend * (pDock->fAlign - .5) * 2);
984 	//int iX = pPointedIcon->fDrawX + pPointedIcon->fWidth * pPointedIcon->fScale / 2 + (pDock->iOffsetForExtend * (pDock->fAlign - .5) * 2);
985 	int iX = pPointedIcon->fDrawX + pPointedIcon->fWidth * pPointedIcon->fScale / 2;
986 	if (pSubDock->container.bIsHorizontal == pDock->container.bIsHorizontal)
987 	{
988 		pSubDock->fAlign = 0.5;
989 		pSubDock->iGapX = iX + pDock->container.iWindowPositionX - gldi_dock_get_screen_offset_x (pDock) - gldi_dock_get_screen_width (pDock) / 2;  // here, sub-docks have an alignment of 0.5
990 		pSubDock->iGapY = pDock->iGapY + pDock->iActiveHeight;
991 	}
992 	else
993 	{
994 		pSubDock->fAlign = (pDock->container.bDirectionUp ? 1 : 0);
995 		pSubDock->iGapX = (pDock->iGapY + pDock->iActiveHeight) * (pDock->container.bDirectionUp ? -1 : 1);
996 		if (pDock->container.bDirectionUp)
997 			pSubDock->iGapY = gldi_dock_get_screen_width (pDock) - (iX + pDock->container.iWindowPositionX - gldi_dock_get_screen_offset_x (pDock)) - pSubDock->iMaxDockHeight / 2;  // sub-docks have an alignment of 1
998 		else
999 			pSubDock->iGapY = iX + pDock->container.iWindowPositionX - pSubDock->iMaxDockHeight / 2;  // sub-docks have an alignment of 0
1000 	}
1001 }
1002 
1003 
cairo_dock_get_first_drawn_element_linear(GList * icons)1004 GList *cairo_dock_get_first_drawn_element_linear (GList *icons)
1005 {
1006 	Icon *icon;
1007 	GList *ic;
1008 	GList *pFirstDrawnElement = NULL;
1009 	for (ic = icons; ic != NULL; ic = ic->next)
1010 	{
1011 		icon = ic->data;
1012 		if (icon->bPointed)
1013 			break ;
1014 	}
1015 
1016 	if (ic == NULL || ic->next == NULL)  // last icon or no pointed icon.
1017 		pFirstDrawnElement = icons;
1018 	else
1019 		pFirstDrawnElement = ic->next;
1020 	return pFirstDrawnElement;
1021 }
1022 
1023 
cairo_dock_show_subdock(Icon * pPointedIcon,CairoDock * pParentDock)1024 void cairo_dock_show_subdock (Icon *pPointedIcon, CairoDock *pParentDock)
1025 {
1026 	cd_debug ("we show the child dock");
1027 	CairoDock *pSubDock = pPointedIcon->pSubDock;
1028 	g_return_if_fail (pSubDock != NULL);
1029 
1030 	if (gldi_container_is_visible (CAIRO_CONTAINER (pSubDock)))  // already visible.
1031 	{
1032 		if (pSubDock->bIsShrinkingDown)  // It's decreasing, we reverse the process.
1033 		{
1034 			cairo_dock_start_growing (pSubDock);
1035 		}
1036 		return ;
1037 	}
1038 
1039 	// place the sub-dock
1040 	pSubDock->pRenderer->set_subdock_position (pPointedIcon, pParentDock);
1041 
1042 	int iNewWidth = pSubDock->iMaxDockWidth;
1043 	int iNewHeight = pSubDock->iMaxDockHeight;
1044 	int iNewPositionX, iNewPositionY;
1045 	cairo_dock_get_window_position_at_balance (pSubDock, iNewWidth, iNewHeight, &iNewPositionX, &iNewPositionY);
1046 
1047 	gtk_window_present (GTK_WINDOW (pSubDock->container.pWidget));
1048 
1049 	if (pSubDock->container.bIsHorizontal)
1050 	{
1051 		gdk_window_move_resize (gldi_container_get_gdk_window (CAIRO_CONTAINER (pSubDock)),
1052 			iNewPositionX,
1053 			iNewPositionY,
1054 			iNewWidth,
1055 			iNewHeight);
1056 	}
1057 	else
1058 	{
1059 		gdk_window_move_resize (gldi_container_get_gdk_window (CAIRO_CONTAINER (pSubDock)),
1060 			iNewPositionY,
1061 			iNewPositionX,
1062 			iNewHeight,
1063 			iNewWidth);
1064 		/* in this case, the sub-dock is over the label, so this one is drawn
1065 		 * with a low transparency, so we trigger the redraw.
1066 		 */
1067 		gtk_widget_queue_draw (pParentDock->container.pWidget);
1068 	}
1069 
1070 	// animate it
1071 	if (myDocksParam.bAnimateSubDock && pSubDock->icons != NULL)
1072 	{
1073 		pSubDock->fFoldingFactor = .99;
1074 		cairo_dock_start_growing (pSubDock);  // We start growing icons
1075 		/* We re-compute icons' size because the first draw was done with
1076 		 * parameters of an hidden dock ; or the showed animation can take
1077 		 * more time than the hidden one.
1078 		 */
1079 		pSubDock->pRenderer->calculate_icons (pSubDock);
1080 	}
1081 	else
1082 	{
1083 		pSubDock->fFoldingFactor = 0;
1084 		///gtk_widget_queue_draw (pSubDock->container.pWidget);
1085 	}
1086 	gldi_object_notify (pPointedIcon, NOTIFICATION_UNFOLD_SUBDOCK, pPointedIcon);
1087 
1088 	gldi_dialogs_replace_all ();
1089 }
1090 
1091 
_cairo_dock_dock_is_child(CairoDock * pCurrentDock,CairoDock * pSubDock)1092 static gboolean _cairo_dock_dock_is_child (CairoDock *pCurrentDock, CairoDock *pSubDock)
1093 {
1094 	GList *pIconsList;
1095 	Icon *pIcon;
1096 	// check all icons of this dock (recursively)
1097 	for (pIconsList = pCurrentDock->icons; pIconsList != NULL; pIconsList = pIconsList->next)
1098 	{
1099 		pIcon = pIconsList->data;
1100 		if (pIcon->pSubDock != NULL
1101 		&& (pIcon->pSubDock == pSubDock // this subdock is inside the current dock!
1102 			|| _cairo_dock_dock_is_child (pIcon->pSubDock, pSubDock))) // check recursively
1103 			return TRUE;
1104 	}
1105 	return FALSE;
1106 }
_add_one_dock_to_list(G_GNUC_UNUSED const gchar * cName,CairoDock * pDock,gpointer * data)1107 static void _add_one_dock_to_list (G_GNUC_UNUSED const gchar *cName, CairoDock *pDock, gpointer *data)
1108 {
1109 	CairoDock *pParentDock = data[0];
1110 	CairoDock *pSubDock = data[1];
1111 
1112 	// get user docks only
1113 	Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pDock, NULL);
1114 	if (pPointingIcon && ! GLDI_OBJECT_IS_STACK_ICON (pPointingIcon))
1115 		// avoid sub-docks that are not from the theme (applet sub-docks, class sub-docks, etc).
1116 		return;
1117 
1118 	// ignore the parent dock.
1119 	if (pDock == pParentDock)
1120 		return;
1121 
1122 	// ignore any child sub-dock (if it's a subdock).
1123 	if (pSubDock != NULL
1124 	&& (pSubDock == pDock || _cairo_dock_dock_is_child (pSubDock, pDock)))
1125 		return;
1126 
1127 	data[2] = g_list_prepend (data[2], pDock);
1128 }
cairo_dock_get_available_docks(CairoDock * pParentDock,CairoDock * pSubDock)1129 GList *cairo_dock_get_available_docks (CairoDock *pParentDock, CairoDock *pSubDock)  // avoid 'pParentDock', and 'pSubDock' and any of its children
1130 {
1131 	gpointer data[3] = {pParentDock, pSubDock, NULL};
1132 	gldi_docks_foreach ((GHFunc)_add_one_dock_to_list, data);
1133 	return data[2];
1134 }
1135 
1136 
_redraw_subdock_content_idle(Icon * pIcon)1137 static gboolean _redraw_subdock_content_idle (Icon *pIcon)
1138 {
1139 	CairoDock *pDock = CAIRO_DOCK(cairo_dock_get_icon_container (pIcon));
1140 	if (pDock != NULL)
1141 	{
1142 		if (pIcon->pSubDock != NULL)
1143 		{
1144 			cairo_dock_draw_subdock_content_on_icon (pIcon, pDock);
1145 		}
1146 		else
1147 		{
1148 			/* the icon could lose its sub-dock in the meantime
1149 			(e.g. a class having 2 icons and we remove one of these icons)
1150 			 */
1151 			cairo_dock_reload_icon_image (pIcon, CAIRO_CONTAINER (pDock));
1152 		}
1153 		cairo_dock_redraw_icon (pIcon);
1154 		if (pDock->iRefCount != 0 && ! pIcon->bDamaged)  // now that the icon image is correct, redraw the pointing icon if needed
1155 			cairo_dock_trigger_redraw_subdock_content (pDock);
1156 	}
1157 	pIcon->iSidRedrawSubdockContent = 0;
1158 	return FALSE;
1159 }
cairo_dock_trigger_redraw_subdock_content(CairoDock * pDock)1160 void cairo_dock_trigger_redraw_subdock_content (CairoDock *pDock)
1161 {
1162 	Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pDock, NULL);
1163 	//g_print ("%s (%s, %d)\n", __func__, pPointingIcon?pPointingIcon->cName:NULL, pPointingIcon?pPointingIcon->iSubdockViewType:0);
1164 	if (pPointingIcon != NULL && (pPointingIcon->iSubdockViewType != 0 || (pPointingIcon->cClass != NULL && ! myIndicatorsParam.bUseClassIndic && (CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (pPointingIcon) || GLDI_OBJECT_IS_LAUNCHER_ICON (pPointingIcon)))))
1165 	{
1166 		/* if we already have an expected re-draw, we go to the end in order to
1167 		 * not do it before the redraw of icon linked to this trigger
1168 		 */
1169 		if (pPointingIcon->iSidRedrawSubdockContent != 0)
1170 			g_source_remove (pPointingIcon->iSidRedrawSubdockContent);
1171 		pPointingIcon->iSidRedrawSubdockContent = g_idle_add ((GSourceFunc) _redraw_subdock_content_idle, pPointingIcon);
1172 	}
1173 }
1174 
cairo_dock_trigger_redraw_subdock_content_on_icon(Icon * icon)1175 void cairo_dock_trigger_redraw_subdock_content_on_icon (Icon *icon)
1176 {
1177 	if (icon->iSidRedrawSubdockContent != 0)
1178 		g_source_remove (icon->iSidRedrawSubdockContent);
1179 	icon->iSidRedrawSubdockContent = g_idle_add ((GSourceFunc) _redraw_subdock_content_idle, icon);
1180 }
1181 
cairo_dock_redraw_subdock_content(CairoDock * pDock)1182 void cairo_dock_redraw_subdock_content (CairoDock *pDock)
1183 {
1184 	CairoDock *pParentDock = NULL;
1185 	Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pDock, &pParentDock);
1186 	if (pPointingIcon != NULL && pPointingIcon->iSubdockViewType != 0 && pPointingIcon->iSidRedrawSubdockContent == 0 && pParentDock != NULL)
1187 	{
1188 		cairo_dock_draw_subdock_content_on_icon (pPointingIcon, pParentDock);
1189 		cairo_dock_redraw_icon (pPointingIcon);
1190 	}
1191 }
1192 
_update_WM_icons(CairoDock * pDock)1193 static gboolean _update_WM_icons (CairoDock *pDock)
1194 {
1195 	cairo_dock_set_icons_geometry_for_window_manager (pDock);
1196 	pDock->iSidUpdateWMIcons = 0;
1197 	return FALSE;
1198 }
cairo_dock_trigger_set_WM_icons_geometry(CairoDock * pDock)1199 void cairo_dock_trigger_set_WM_icons_geometry (CairoDock *pDock)
1200 {
1201 	if (pDock->iSidUpdateWMIcons == 0)
1202 	{
1203 		pDock->iSidUpdateWMIcons = g_idle_add ((GSourceFunc) _update_WM_icons, pDock);
1204 	}
1205 }
1206 
cairo_dock_resize_icon_in_dock(Icon * pIcon,CairoDock * pDock)1207 void cairo_dock_resize_icon_in_dock (Icon *pIcon, CairoDock *pDock)  // resize the icon according to the requested size previously set on the icon.
1208 {
1209 	cairo_dock_set_icon_size_in_dock (pDock, pIcon);
1210 
1211 	cairo_dock_load_icon_image (pIcon, CAIRO_CONTAINER (pDock));  // handles the applet's context
1212 
1213 	if (cairo_dock_get_icon_data_renderer (pIcon) != NULL)
1214 		cairo_dock_reload_data_renderer_on_icon (pIcon, CAIRO_CONTAINER (pDock));
1215 
1216 	cairo_dock_trigger_update_dock_size (pDock);
1217 	gtk_widget_queue_draw (pDock->container.pWidget);
1218 }
1219 
1220 
1221   ///////////////////////
1222  /// DOCK BACKGROUND ///
1223 ///////////////////////
1224 
_cairo_dock_make_stripes_background(int iWidth,int iHeight,GldiColor * fStripesColorBright,GldiColor * fStripesColorDark,int iNbStripes,double fStripesWidth,double fStripesAngle)1225 static cairo_surface_t *_cairo_dock_make_stripes_background (int iWidth, int iHeight, GldiColor *fStripesColorBright, GldiColor *fStripesColorDark, int iNbStripes, double fStripesWidth, double fStripesAngle)
1226 {
1227 	cairo_pattern_t *pStripesPattern;
1228 	if (fabs (fStripesAngle) != 90)
1229 		pStripesPattern = cairo_pattern_create_linear (0.0f,
1230 			0.0f,
1231 			iWidth,
1232 			iWidth * tan (fStripesAngle * G_PI/180.));
1233 	else
1234 		pStripesPattern = cairo_pattern_create_linear (0.0f,
1235 			0.0f,
1236 			0.,
1237 			(fStripesAngle == 90) ? iHeight : - iHeight);
1238 	g_return_val_if_fail (cairo_pattern_status (pStripesPattern) == CAIRO_STATUS_SUCCESS, NULL);
1239 
1240 	cairo_pattern_set_extend (pStripesPattern, CAIRO_EXTEND_REPEAT);
1241 
1242 	if (iNbStripes > 0)
1243 	{
1244 		gdouble fStep;
1245 		int i;
1246 		for (i = 0; i < iNbStripes+1; i ++)
1247 		{
1248 			fStep = (double)i / iNbStripes;
1249 			cairo_pattern_add_color_stop_rgba (pStripesPattern,
1250 				fStep - fStripesWidth / 2.,
1251 				fStripesColorBright->rgba.red,
1252 				fStripesColorBright->rgba.green,
1253 				fStripesColorBright->rgba.blue,
1254 				fStripesColorBright->rgba.alpha);
1255 			cairo_pattern_add_color_stop_rgba (pStripesPattern,
1256 				fStep,
1257 				fStripesColorDark->rgba.red,
1258 				fStripesColorDark->rgba.green,
1259 				fStripesColorDark->rgba.blue,
1260 				fStripesColorDark->rgba.alpha);
1261 			cairo_pattern_add_color_stop_rgba (pStripesPattern,
1262 				fStep + fStripesWidth / 2.,
1263 				fStripesColorBright->rgba.red,
1264 				fStripesColorBright->rgba.green,
1265 				fStripesColorBright->rgba.blue,
1266 				fStripesColorBright->rgba.alpha);
1267 		}
1268 	}
1269 	else
1270 	{
1271 		cairo_pattern_add_color_stop_rgba (pStripesPattern,
1272 			0.,
1273 			fStripesColorDark->rgba.red,
1274 			fStripesColorDark->rgba.green,
1275 			fStripesColorDark->rgba.blue,
1276 			fStripesColorDark->rgba.alpha);
1277 		cairo_pattern_add_color_stop_rgba (pStripesPattern,
1278 			1.,
1279 			fStripesColorBright->rgba.red,
1280 			fStripesColorBright->rgba.green,
1281 			fStripesColorBright->rgba.blue,
1282 			fStripesColorBright->rgba.alpha);
1283 	}
1284 
1285 	cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
1286 			iWidth,
1287 			iHeight);
1288 	cairo_t *pImageContext = cairo_create (pNewSurface);
1289 	cairo_set_source (pImageContext, pStripesPattern);
1290 	cairo_paint (pImageContext);
1291 
1292 	cairo_pattern_destroy (pStripesPattern);
1293 	cairo_destroy (pImageContext);
1294 
1295 	return pNewSurface;
1296 }
_cairo_dock_load_default_background(CairoDockImageBuffer * pImage,int iWidth,int iHeight)1297 static void _cairo_dock_load_default_background (CairoDockImageBuffer *pImage, int iWidth, int iHeight)
1298 {
1299 	cd_debug ("%s (%s, %d, %dx%d)", __func__, myDocksParam.cBackgroundImageFile, myDocksParam.bBackgroundImageRepeat, iWidth, iHeight);
1300 	if (myDocksParam.bUseDefaultColors)
1301 	{
1302 		cairo_surface_t *pBgSurface = cairo_dock_create_blank_surface (
1303 			iWidth,
1304 			iHeight);
1305 		cairo_t *pImageContext = cairo_create (pBgSurface);
1306 
1307 		/* Add a small vertical gradation to the bg color, it looks better than
1308 		 * a completely monochrome background. At the top is the original color
1309 		 * which connects nicely with other items (labels, menus, dialogs)
1310 		 */
1311 		GldiColor bg_color, bg_color2;
1312 		gldi_style_color_get (GLDI_COLOR_BG, &bg_color);
1313 		gldi_style_color_shade (&bg_color, GLDI_COLOR_SHADE_LIGHT, &bg_color2);
1314 
1315 		cairo_pattern_t *pattern = cairo_pattern_create_linear (0, 0, 0, iHeight);
1316 		cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
1317 		cairo_pattern_add_color_stop_rgba (pattern,
1318 			1.,
1319 			bg_color.rgba.red, bg_color.rgba.green, bg_color.rgba.blue, bg_color.rgba.alpha);  // this will be at the bottom of the dock
1320 		cairo_pattern_add_color_stop_rgba (pattern,
1321 			0.5,
1322 			bg_color2.rgba.red, bg_color2.rgba.green, bg_color2.rgba.blue, bg_color2.rgba.alpha);  // middle
1323 		cairo_pattern_add_color_stop_rgba (pattern,
1324 			0.,
1325 			bg_color.rgba.red, bg_color.rgba.green, bg_color.rgba.blue, bg_color.rgba.alpha);  // and this is at the top
1326 		cairo_set_source (pImageContext, pattern);
1327 		///gldi_style_colors_set_bg_color (pImageContext);
1328 
1329 		cairo_pattern_destroy (pattern);
1330 		cairo_paint (pImageContext);
1331 		cairo_destroy (pImageContext);
1332 		cairo_dock_load_image_buffer_from_surface (pImage,
1333 			pBgSurface,
1334 			iWidth,
1335 			iHeight);
1336 	}
1337 	else if (myDocksParam.cBackgroundImageFile != NULL)
1338 	{
1339 		if (myDocksParam.bBackgroundImageRepeat)
1340 		{
1341 			cairo_surface_t *pBgSurface = cairo_dock_create_surface_from_pattern (myDocksParam.cBackgroundImageFile,
1342 				iWidth,
1343 				iHeight,
1344 				myDocksParam.fBackgroundImageAlpha);
1345 			cairo_dock_load_image_buffer_from_surface (pImage,
1346 				pBgSurface,
1347 				iWidth,
1348 				iHeight);
1349 		}
1350 		else
1351 		{
1352 			cairo_dock_load_image_buffer_full (pImage,
1353 				myDocksParam.cBackgroundImageFile,
1354 				iWidth,
1355 				iHeight,
1356 				CAIRO_DOCK_FILL_SPACE,
1357 				myDocksParam.fBackgroundImageAlpha);
1358 		}
1359 	}
1360 	if (pImage->pSurface == NULL)
1361 	{
1362 		cairo_surface_t *pBgSurface = _cairo_dock_make_stripes_background (
1363 			iWidth,
1364 			iHeight,
1365 			&myDocksParam.fStripesColorBright,
1366 			&myDocksParam.fStripesColorDark,
1367 			myDocksParam.iNbStripes,
1368 			myDocksParam.fStripesWidth,
1369 			myDocksParam.fStripesAngle);
1370 		cairo_dock_load_image_buffer_from_surface (pImage,
1371 			pBgSurface,
1372 			iWidth,
1373 			iHeight);
1374 	}
1375 }
1376 
cairo_dock_load_dock_background(CairoDock * pDock)1377 void cairo_dock_load_dock_background (CairoDock *pDock)
1378 {
1379 	cairo_dock_unload_image_buffer (&pDock->backgroundBuffer);
1380 
1381 	int iWidth = pDock->iDecorationsWidth;
1382 	int iHeight = pDock->iDecorationsHeight;
1383 
1384 	if (pDock->bGlobalBg || pDock->iRefCount > 0)
1385 	{
1386 		_cairo_dock_load_default_background (&pDock->backgroundBuffer, iWidth, iHeight);
1387 	}
1388 	else if (pDock->cBgImagePath != NULL)
1389 	{
1390 		cairo_dock_load_image_buffer (&pDock->backgroundBuffer, pDock->cBgImagePath, iWidth, iHeight, CAIRO_DOCK_FILL_SPACE);
1391 	}
1392 	if (pDock->backgroundBuffer.pSurface == NULL)
1393 	{
1394 		cairo_surface_t *pSurface = _cairo_dock_make_stripes_background (iWidth, iHeight, &pDock->fBgColorBright, &pDock->fBgColorDark, 0, 0., 90);
1395 		cairo_dock_load_image_buffer_from_surface (&pDock->backgroundBuffer, pSurface, iWidth, iHeight);
1396 	}
1397 	gtk_widget_queue_draw (pDock->container.pWidget);
1398 }
1399 
_load_background_idle(CairoDock * pDock)1400 static gboolean _load_background_idle (CairoDock *pDock)
1401 {
1402 	cairo_dock_load_dock_background (pDock);
1403 
1404 	pDock->iSidLoadBg = 0;
1405 	return FALSE;
1406 }
cairo_dock_trigger_load_dock_background(CairoDock * pDock)1407 void cairo_dock_trigger_load_dock_background (CairoDock *pDock)
1408 {
1409 	if (pDock->iDecorationsWidth == pDock->backgroundBuffer.iWidth && pDock->iDecorationsHeight == pDock->backgroundBuffer.iHeight)  // mise a jour inutile.
1410 		return;
1411 	if (pDock->iSidLoadBg == 0)
1412 		pDock->iSidLoadBg = g_idle_add ((GSourceFunc)_load_background_idle, pDock);
1413 }
1414 
1415 
cairo_dock_make_preview(CairoDock * pDock,const gchar * cPreviewPath)1416 void cairo_dock_make_preview (CairoDock *pDock, const gchar *cPreviewPath)
1417 {
1418 	if (pDock && pDock->pRenderer)
1419 	{
1420 		// place the mouse in the middle of the dock and update the icons position
1421 		pDock->container.iMouseX = pDock->container.iWidth/2;
1422 		pDock->container.iMouseY = 1;
1423 		cairo_dock_calculate_dock_icons (pDock);
1424 
1425 		// dump the context into a cairo-surface
1426 		cairo_surface_t *pSurface;
1427 		int w = (pDock->container.bIsHorizontal ? pDock->container.iWidth : pDock->container.iHeight);  // iActiveWidth
1428 		int h = (pDock->container.bIsHorizontal ? pDock->container.iHeight : pDock->container.iWidth);  // iActiveHeight
1429 		GLubyte *glbuffer = NULL;
1430 		if (g_bUseOpenGL)
1431 		{
1432 			if (gldi_gl_container_begin_draw (CAIRO_CONTAINER (pDock)))
1433 			{
1434 				pDock->pRenderer->render_opengl (pDock);
1435 			}
1436 			int s = 4;  // 4 channels of 1 byte each (rgba).
1437 			GLubyte *buffer = (GLubyte *) g_malloc (w * h * s);
1438 			glbuffer = (GLubyte *) g_malloc (w * h * s);
1439 
1440 			glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)buffer);
1441 
1442 			// make upside down
1443 			int x, y;
1444 			for (y=0; y<h; y++) {
1445 				for (x=0; x<w*s; x++) {
1446 					glbuffer[y * s * w + x] = buffer[(h - y - 1) * w * s + x];
1447 				}
1448 			}
1449 
1450 			int iStride = w * s;  // number of bytes between the beginning of the 2 lines
1451 			pSurface = cairo_image_surface_create_for_data ((guchar *)glbuffer,
1452 				CAIRO_FORMAT_ARGB32,
1453 				w,
1454 				h,
1455 				iStride);
1456 
1457 			g_free (buffer);
1458 		}
1459 		else
1460 		{
1461 			pSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1462 				w,
1463 				h);
1464 			cairo_t *pCairoContext = cairo_create (pSurface);
1465 			pDock->pRenderer->render (pCairoContext, pDock);
1466 			cairo_destroy (pCairoContext);
1467 		}
1468 		// dump the surface into a PNG
1469 		if (!pDock->container.bIsHorizontal)
1470 		{
1471 			cairo_t *pCairoContext = cairo_create (pSurface);
1472 			cairo_translate (pCairoContext, w/2, h/2);
1473 			cairo_rotate (pCairoContext, -G_PI/2);
1474 			cairo_translate (pCairoContext, -h/2, -w/2);
1475 			cairo_destroy (pCairoContext);
1476 		}
1477 
1478 		cairo_surface_write_to_png (pSurface, cPreviewPath);
1479 		cairo_surface_destroy (pSurface);
1480 		g_free (glbuffer);
1481 	}
1482 }
1483