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 <GL/gl.h>
22 #include <GL/glu.h>
23 
24 #include "cairo-dock-separator-manager.h"  // gldi_auto_separator_icon_new
25 #include "cairo-dock-log.h"
26 #include "cairo-dock-draw-opengl.h"  // for the redirected texture
27 #include "cairo-dock-data-renderer.h"  // cairo_dock_reload_data_renderer_on_icon/cairo_dock_refresh_data_renderer
28 #include "cairo-dock-windows-manager.h"  // gldi_windows_get_active
29 #include "cairo-dock-indicator-manager.h"  // myIndicators.bUseClassIndic
30 #include "cairo-dock-draw.h"
31 #include "cairo-dock-animations.h"
32 #include "cairo-dock-image-buffer.h"
33 #include "cairo-dock-module-manager.h"  // CAIRO_DOCK_MODULE_CAN_DESKLET
34 #include "cairo-dock-module-instance-manager.h"  // pModuleInstance->
35 #include "cairo-dock-icon-factory.h"
36 #include "cairo-dock-icon-facility.h"
37 #include "cairo-dock-applications-manager.h"  // myTaskbarParam.bHideVisibleApplis
38 #include "cairo-dock-stack-icon-manager.h"
39 #include "cairo-dock-separator-manager.h"
40 #include "cairo-dock-class-icon-manager.h"
41 #include "cairo-dock-application-facility.h"
42 #include "cairo-dock-launcher-manager.h"
43 #include "cairo-dock-config.h"  // cairo_dock_is_loading
44 #include "cairo-dock-dock-facility.h"
45 #include "cairo-dock-log.h"
46 #include "cairo-dock-menu.h"  // gldi_menu_popup
47 #include "cairo-dock-dock-manager.h"
48 #include "cairo-dock-dock-visibility.h"  // gldi_dock_search_overlapping_window
49 #include "cairo-dock-flying-container.h"
50 #include "cairo-dock-backends-manager.h"
51 #include "cairo-dock-class-manager.h"  // cairo_dock_check_class_subdock_is_empty
52 #include "cairo-dock-desktop-manager.h"
53 #include "cairo-dock-windows-manager.h"  // gldi_windows_get_active
54 #include "cairo-dock-dock-factory.h"
55 
56 // dependencies
57 extern CairoDockHidingEffect *g_pHidingBackend;
58 extern CairoDockHidingEffect *g_pKeepingBelowBackend;
59 extern gboolean g_bUseOpenGL;
60 extern CairoDockGLConfig g_openglConfig;
61 
62 // private
63 static Icon *s_pIconClicked = NULL;  // pour savoir quand on deplace une icone a la souris. Dangereux si l'icone se fait effacer en cours ...
64 static int s_iClickX, s_iClickY;  // coordonnees du clic dans le dock, pour pouvoir initialiser le deplacement apres un seuil.
65 static int s_iSidShowSubDockDemand = 0;
66 static int s_iSidActionOnDragHover = 0;
67 static CairoDock *s_pDockShowingSubDock = NULL;  // on n'accede pas a son contenu, seulement l'adresse.
68 static CairoDock *s_pSubDockShowing = NULL;  // on n'accede pas a son contenu, seulement l'adresse.
69 static CairoFlyingContainer *s_pFlyingContainer = NULL;
70 static int s_iFirstClickX=0, s_iFirstClickY=0;  // for double-click.
71 static gboolean s_bFrozenDock = FALSE;
72 static gboolean s_bIconDragged = FALSE;
73 static gboolean _check_mouse_outside (CairoDock *pDock);
74 static void cairo_dock_stop_icon_glide (CairoDock *pDock);
75 #define CD_CLICK_ZONE 5
76 
77   /////////////////
78  /// CALLBACKS ///
79 /////////////////
80 
_mouse_is_really_outside(CairoDock * pDock)81 static gboolean _mouse_is_really_outside (CairoDock *pDock)
82 {
83 	int x1, x2, y1, y2;
84 	if (pDock->iInputState == CAIRO_DOCK_INPUT_ACTIVE)
85 	{
86 		x1 = (pDock->container.iWidth - pDock->iActiveWidth) * pDock->fAlign;
87 		x2 = x1 + pDock->iActiveWidth;
88 		if (pDock->container.bDirectionUp)
89 		{
90 			y1 = pDock->container.iHeight - pDock->iActiveHeight + 1;
91 			y2 = pDock->container.iHeight;
92 		}
93 		else
94 		{
95 			y1 = 0;
96 			y2 = pDock->iActiveHeight - 1;
97 		}
98 	}
99 	else if (pDock->iInputState == CAIRO_DOCK_INPUT_AT_REST)
100 	{
101 		x1 = (pDock->container.iWidth - pDock->iMinDockWidth) * pDock->fAlign;
102 		x2 = x1 + pDock->iMinDockWidth;
103 		if (pDock->container.bDirectionUp)
104 		{
105 			y1 = pDock->container.iHeight - pDock->iMinDockHeight + 1;
106 			y2 = pDock->container.iHeight;
107 		}
108 		else
109 		{
110 			y1 = 0;
111 			y2 = pDock->iMinDockHeight - 1;
112 		}
113 	}
114 	else  // hidden
115 		return TRUE;
116 	if (pDock->container.iMouseX <= x1
117 	|| pDock->container.iMouseX >= x2)
118 		return TRUE;
119 	if (pDock->container.iMouseY < y1
120 	|| pDock->container.iMouseY > y2)  // Note: Compiz has a bug: when using the "cube rotation" plug-in, it will reserve 2 pixels for itself on the left and right edges of the screen. So the mouse is not inside the dock when it's at x=0 or x=Ws-1 (no 'enter' event is sent; it's as if the x=0 or x=Ws-1 vertical line of pixels is out of the screen).
121 		return TRUE;
122 
123 	return FALSE;
124 }
125 
cairo_dock_freeze_docks(gboolean bFreeze)126 void cairo_dock_freeze_docks (gboolean bFreeze)
127 {
128 	s_bFrozenDock = bFreeze;  /// instead, try to connect to the motion-event and intercept it ...
129 }
130 
_on_expose(G_GNUC_UNUSED GtkWidget * pWidget,cairo_t * pCairoContext,CairoDock * pDock)131 static gboolean _on_expose (G_GNUC_UNUSED GtkWidget *pWidget, cairo_t *pCairoContext, CairoDock *pDock)
132 {
133 	if (g_bUseOpenGL && pDock->pRenderer->render_opengl != NULL)  // OpenGL rendering
134 	{
135 		GdkRectangle area;
136 		double x1, x2, y1, y2;
137 		cairo_clip_extents (pCairoContext, &x1, &y1, &x2, &y2);
138 		area.x = x1;
139 		area.y = y1;
140 		area.width = x2 - x1;
141 		area.height = y2 - y1;
142 
143 		if (! gldi_gl_container_begin_draw_full (CAIRO_CONTAINER (pDock), area.x + area.y != 0 ? &area : NULL, TRUE))
144 			return FALSE;
145 
146 		if (cairo_dock_is_loading ())
147 		{
148 			// don't draw anything, just let it transparent
149 		}
150 		else if (cairo_dock_is_hidden (pDock) && (g_pHidingBackend == NULL || !g_pHidingBackend->bCanDisplayHiddenDock))
151 		{
152 			cairo_dock_render_hidden_dock_opengl (pDock);
153 		}
154 		else
155 		{
156 			gldi_object_notify (pDock, NOTIFICATION_RENDER, pDock, NULL);
157 		}
158 
159 		gldi_gl_container_end_draw (CAIRO_CONTAINER (pDock));
160 	}
161 	else if (! g_bUseOpenGL && pDock->pRenderer->render != NULL)  // cairo rendering
162 	{
163 		cairo_dock_init_drawing_context_on_container (CAIRO_CONTAINER (pDock), pCairoContext);
164 
165 		if (cairo_dock_is_loading ())
166 		{
167 			// don't draw anything, just let it transparent
168 		}
169 		else if (cairo_dock_is_hidden (pDock) && (g_pHidingBackend == NULL || !g_pHidingBackend->bCanDisplayHiddenDock))
170 		{
171 			cairo_dock_render_hidden_dock (pCairoContext, pDock);
172 		}
173 		else
174 		{
175 			gldi_object_notify (pDock, NOTIFICATION_RENDER, pDock, pCairoContext);
176 		}
177 	}
178 	return FALSE;
179 }
180 
181 
_emit_leave_signal_delayed(CairoDock * pDock)182 static gboolean _emit_leave_signal_delayed (CairoDock *pDock)
183 {
184 	//g_print ("%s(%d)\n", __func__, pDock->iRefCount);
185 	cairo_dock_emit_leave_signal (CAIRO_CONTAINER (pDock));
186 	pDock->iSidLeaveDemand = 0;
187 	return FALSE;
188 }
_cairo_dock_show_sub_dock_delayed(CairoDock * pDock)189 static gboolean _cairo_dock_show_sub_dock_delayed (CairoDock *pDock)
190 {
191 	s_iSidShowSubDockDemand = 0;
192 	s_pDockShowingSubDock = NULL;
193 	s_pSubDockShowing = NULL;
194 	Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);
195 	//g_print ("%s (%x, %x)", __func__, icon, icon ? icon->pSubDock:0);
196 	if (icon != NULL && icon->pSubDock != NULL)
197 		cairo_dock_show_subdock (icon, pDock);
198 
199 	return FALSE;
200 }
_search_icon(Icon * icon,gpointer * data)201 static void _search_icon (Icon *icon, gpointer *data)
202 {
203 	if (icon == data[0])
204 		data[1] = icon;
205 }
_cairo_dock_action_on_drag_hover(Icon * pIcon)206 static gboolean _cairo_dock_action_on_drag_hover (Icon *pIcon)
207 {
208 	gpointer data[2] = {pIcon, NULL};
209 	gldi_icons_foreach_in_docks ((GldiIconFunc)_search_icon, data);  // on verifie que l'icone ne s'est pas faite effacee entre-temps.
210 	pIcon = data[1];
211 	if (pIcon && pIcon->iface.action_on_drag_hover)
212 		pIcon->iface.action_on_drag_hover (pIcon);
213 	s_iSidActionOnDragHover = 0;
214 	return FALSE;
215 }
_on_change_icon(Icon * pLastPointedIcon,Icon * pPointedIcon,CairoDock * pDock)216 static void _on_change_icon (Icon *pLastPointedIcon, Icon *pPointedIcon, CairoDock *pDock)
217 {
218 	//g_print ("%s (%s -> %s)\n", __func__, pLastPointedIcon?pLastPointedIcon->cName:"none", pPointedIcon?pPointedIcon->cName:"none");
219 	//cd_debug ("on change d'icone dans %x (-> %s)", pDock, (pPointedIcon != NULL ? pPointedIcon->cName : "rien"));
220 	if (s_iSidShowSubDockDemand != 0 && pDock == s_pDockShowingSubDock)
221 	{
222 		//cd_debug ("on annule la demande de montrage de sous-dock");
223 		g_source_remove (s_iSidShowSubDockDemand);
224 		s_iSidShowSubDockDemand = 0;
225 		s_pDockShowingSubDock = NULL;
226 		s_pSubDockShowing = NULL;
227 	}
228 
229 	// take action when dragging something onto an icon
230 	if (s_iSidActionOnDragHover != 0)
231 	{
232 		//cd_debug ("on annule la demande de montrage d'appli");
233 		g_source_remove (s_iSidActionOnDragHover);
234 		s_iSidActionOnDragHover = 0;
235 	}
236 
237 	if (pDock->bIsDragging && pPointedIcon && pPointedIcon->iface.action_on_drag_hover)
238 	{
239 		s_iSidActionOnDragHover = g_timeout_add (600, (GSourceFunc) _cairo_dock_action_on_drag_hover, pPointedIcon);
240 	}
241 
242 	// replace dialogs
243 	gldi_dialogs_refresh_all ();
244 
245 	// hide the sub-dock of the previous pointed icon
246 	if (pLastPointedIcon != NULL && pLastPointedIcon->pSubDock != NULL)  // on a quitte une icone ayant un sous-dock.
247 	{
248 		CairoDock *pSubDock = pLastPointedIcon->pSubDock;
249 		if (gldi_container_is_visible (CAIRO_CONTAINER (pSubDock)))  // le sous-dock est visible, on retarde son cachage.
250 		{
251 			//g_print ("on cache %s en changeant d'icone\n", pLastPointedIcon->cName);
252 			if (pSubDock->iSidLeaveDemand == 0)
253 			{
254 				//g_print (" on retarde le cachage du dock de %dms\n", MAX (myDocksParam.iLeaveSubDockDelay, 300));
255 				pSubDock->iSidLeaveDemand = g_timeout_add (MAX (myDocksParam.iLeaveSubDockDelay, 300), (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pSubDock);  // on force le retard meme si iLeaveSubDockDelay est a 0, car lorsqu'on entre dans un sous-dock, il arrive frequemment qu'on glisse hors de l'icone qui pointe dessus, et c'est tres desagreable d'avoir le dock qui se ferme avant d'avoir pu entre dedans.
256 			}
257 		}
258 	}
259 
260 	// show the sub-dock of the current pointed icon
261 	if (pPointedIcon != NULL && pPointedIcon->pSubDock != NULL && (! myDocksParam.bShowSubDockOnClick || CAIRO_DOCK_IS_APPLI (pPointedIcon) || pDock->bIsDragging))  // on entre sur une icone ayant un sous-dock.
262 	{
263 		// if we were leaving the sub-dock, cancel that.
264 		if (pPointedIcon->pSubDock->iSidLeaveDemand != 0)
265 		{
266 			g_source_remove (pPointedIcon->pSubDock->iSidLeaveDemand);
267 			pPointedIcon->pSubDock->iSidLeaveDemand = 0;
268 		}
269 		// and show the sub-dock, possibly with a delay.
270 		if (myDocksParam.iShowSubDockDelay > 0)
271 		{
272 			if (s_iSidShowSubDockDemand != 0)
273 				g_source_remove (s_iSidShowSubDockDemand);
274 			s_iSidShowSubDockDemand = g_timeout_add (myDocksParam.iShowSubDockDelay, (GSourceFunc) _cairo_dock_show_sub_dock_delayed, pDock);  // we can't be showing more than 1 sub-dock, so this timeout can be global to all docks.
275 			s_pDockShowingSubDock = pDock;
276 			s_pSubDockShowing = pPointedIcon->pSubDock;
277 		}
278 		else
279 			cairo_dock_show_subdock (pPointedIcon, pDock);
280 	}
281 
282 	// notify everybody
283 	if (pPointedIcon != NULL && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pPointedIcon))
284 	{
285 		gboolean bStartAnimation = FALSE;
286 		gldi_object_notify (pDock, NOTIFICATION_ENTER_ICON, pPointedIcon, pDock, &bStartAnimation);
287 
288 		if (bStartAnimation)
289 		{
290 			cairo_dock_mark_icon_as_hovered_by_mouse (pPointedIcon);  // mark the animation as 'hover' if it's not already in another state (clicked, etc).
291 			cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
292 		}
293 	}
294 }
295 
296 
cairo_dock_stop_icon_glide(CairoDock * pDock)297 static void cairo_dock_stop_icon_glide (CairoDock *pDock)
298 {
299 	Icon *icon;
300 	GList *ic;
301 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
302 	{
303 		icon = ic->data;
304 		icon->fGlideOffset = 0;
305 		icon->iGlideDirection = 0;
306 	}
307 }
_cairo_dock_make_icon_glide(Icon * pPointedIcon,Icon * pMovingicon,CairoDock * pDock)308 static void _cairo_dock_make_icon_glide (Icon *pPointedIcon, Icon *pMovingicon, CairoDock *pDock)
309 {
310 	Icon *icon;
311 	GList *ic;
312 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
313 	{
314 		icon = ic->data;
315 		if (icon == pMovingicon)
316 			continue;
317 		//if (pDock->container.iMouseX > s_pMovingicon->fDrawXAtRest + s_pMovingicon->fWidth * s_pMovingicon->fScale /2)  // on a deplace l'icone a droite.  // fDrawXAtRest
318 		if (pMovingicon->fXAtRest < pPointedIcon->fXAtRest)  // on a deplace l'icone a droite.
319 		{
320 			//g_print ("%s : %.2f / %.2f ; %.2f / %d (%.2f)\n", icon->cName, icon->fXAtRest, pMovingicon->fXAtRest, icon->fDrawX, pDock->container.iMouseX, icon->fGlideOffset);
321 			if (icon->fXAtRest > pMovingicon->fXAtRest && icon->fDrawX < pDock->container.iMouseX + 5 && icon->fGlideOffset == 0)  // icone entre l'icone deplacee et le curseur.
322 			{
323 				//g_print ("  %s glisse vers la gauche\n", icon->cName);
324 				icon->iGlideDirection = -1;
325 			}
326 			else if (icon->fXAtRest > pMovingicon->fXAtRest && icon->fDrawX > pDock->container.iMouseX && icon->fGlideOffset != 0)
327 			{
328 				//g_print ("  %s glisse vers la droite\n", icon->cName);
329 				icon->iGlideDirection = 1;
330 			}
331 			else if (icon->fXAtRest < pMovingicon->fXAtRest && icon->fGlideOffset > 0)
332 			{
333 				//g_print ("  %s glisse en sens inverse vers la gauche\n", icon->cName);
334 				icon->iGlideDirection = -1;
335 			}
336 		}
337 		else
338 		{
339 			//g_print ("deplacement de %s vers la gauche (%.2f / %d)\n", icon->cName, icon->fDrawX + icon->fWidth * fMaxScale + myIconsParam.iIconGap, pDock->container.iMouseX);
340 			if (icon->fXAtRest < pMovingicon->fXAtRest && icon->fDrawX + icon->image.iWidth + myIconsParam.iIconGap >= pDock->container.iMouseX && icon->fGlideOffset == 0)  // icone entre l'icone deplacee et le curseur.
341 			{
342 				//g_print ("  %s glisse vers la droite\n", icon->cName);
343 				icon->iGlideDirection = 1;
344 			}
345 			else if (icon->fXAtRest < pMovingicon->fXAtRest && icon->fDrawX + icon->image.iWidth + myIconsParam.iIconGap <= pDock->container.iMouseX && icon->fGlideOffset != 0)
346 			{
347 				//g_print ("  %s glisse vers la gauche\n", icon->cName);
348 				icon->iGlideDirection = -1;
349 			}
350 			else if (icon->fXAtRest > pMovingicon->fXAtRest && icon->fGlideOffset < 0)
351 			{
352 				//g_print ("  %s glisse en sens inverse vers la droite\n", icon->cName);
353 				icon->iGlideDirection = 1;
354 			}
355 		}
356 	}
357 }
_on_motion_notify(GtkWidget * pWidget,GdkEventMotion * pMotion,CairoDock * pDock)358 static gboolean _on_motion_notify (GtkWidget* pWidget,
359 	GdkEventMotion* pMotion,
360 	CairoDock *pDock)
361 {
362 	static double fLastTime = 0;
363 	if (s_bFrozenDock && pMotion != NULL && pMotion->time != 0)
364 		return FALSE;
365 	Icon *pPointedIcon=NULL, *pLastPointedIcon = cairo_dock_get_pointed_icon (pDock->icons);
366 	//g_print ("%s (%.2f;%.2f, %d)\n", __func__, pMotion->x, pMotion->y, pDock->iInputState);
367 
368 	if (pMotion != NULL)
369 	{
370 		//g_print ("%s (%d,%d) (%d, %.2fms, bAtBottom:%d; bIsShrinkingDown:%d)\n", __func__, (int) pMotion->x, (int) pMotion->y, pMotion->is_hint, pMotion->time - fLastTime, pDock->bAtBottom, pDock->bIsShrinkingDown);
371 		//\_______________ On deplace le dock si ALT est enfoncee.
372 		if ((pMotion->state & GDK_MOD1_MASK) && (pMotion->state & GDK_BUTTON1_MASK))
373 		{
374 			if (pDock->container.bIsHorizontal)
375 			{
376 				pDock->container.iWindowPositionX = pMotion->x_root - pDock->container.iMouseX;
377 				pDock->container.iWindowPositionY = pMotion->y_root - pDock->container.iMouseY;
378 				gtk_window_move (GTK_WINDOW (pWidget),
379 					pDock->container.iWindowPositionX,
380 					pDock->container.iWindowPositionY);
381 			}
382 			else
383 			{
384 				pDock->container.iWindowPositionX = pMotion->y_root - pDock->container.iMouseX;
385 				pDock->container.iWindowPositionY = pMotion->x_root - pDock->container.iMouseY;
386 				gtk_window_move (GTK_WINDOW (pWidget),
387 					pDock->container.iWindowPositionY,
388 					pDock->container.iWindowPositionX);
389 			}
390 			gdk_device_get_state (pMotion->device, pMotion->window, NULL, NULL);
391 			return FALSE;
392 		}
393 
394 		//\_______________ On recupere la position de la souris.
395 		if (pDock->container.bIsHorizontal)
396 		{
397 			pDock->container.iMouseX = (int) pMotion->x;
398 			pDock->container.iMouseY = (int) pMotion->y;
399 		}
400 		else
401 		{
402 			pDock->container.iMouseX = (int) pMotion->y;
403 			pDock->container.iMouseY = (int) pMotion->x;
404 		}
405 
406 		//\_______________ On tire l'icone volante.
407 		if (s_pFlyingContainer != NULL && ! pDock->container.bInside)
408 		{
409 			gldi_flying_container_drag (s_pFlyingContainer, pDock);
410 		}
411 
412 		//\_______________ On elague le flux des MotionNotify, sinon X en envoie autant que le permet le CPU !
413 		if (pMotion->time != 0 && pMotion->time - fLastTime < myBackendsParam.fRefreshInterval && s_pIconClicked == NULL)
414 		{
415 			gdk_device_get_state (pMotion->device, pMotion->window, NULL, NULL);
416 			return FALSE;
417 		}
418 
419 		//\_______________ On recalcule toutes les icones et on redessine.
420 		pPointedIcon = cairo_dock_calculate_dock_icons (pDock);
421 		//g_print ("pPointedIcon: %s\n", pPointedIcon?pPointedIcon->cName:"none");
422 		gtk_widget_queue_draw (pWidget);
423 		fLastTime = pMotion->time;
424 
425 		//\_______________ On tire l'icone cliquee.
426 		if (s_pIconClicked != NULL && s_pIconClicked->iAnimationState != CAIRO_DOCK_STATE_REMOVE_INSERT && ! myDocksParam.bLockIcons && ! myDocksParam.bLockAll && (fabs (pMotion->x - s_iClickX) > CD_CLICK_ZONE || fabs (pMotion->y - s_iClickY) > CD_CLICK_ZONE) && ! pDock->bPreventDraggingIcons)
427 		{
428 			s_bIconDragged = TRUE;
429 			cairo_dock_mark_icon_as_following_mouse (s_pIconClicked);
430 			//pDock->fAvoidingMouseMargin = .5;
431 			pDock->iAvoidingMouseIconType = s_pIconClicked->iGroup;  // on pourrait le faire lors du clic aussi.
432 			s_pIconClicked->fScale = cairo_dock_get_icon_max_scale (s_pIconClicked);
433 			s_pIconClicked->fDrawX = pDock->container.iMouseX  - s_pIconClicked->fWidth * s_pIconClicked->fScale / 2;
434 			s_pIconClicked->fDrawY = pDock->container.iMouseY - s_pIconClicked->fHeight * s_pIconClicked->fScale / 2 ;
435 			s_pIconClicked->fAlpha = 0.75;
436 		}
437 
438 		//gdk_event_request_motions (pMotion);  // ce sera pour GDK 2.12.
439 		gdk_device_get_state (pMotion->device, pMotion->window, NULL, NULL);  // pour recevoir d'autres MotionNotify.
440 	}
441 	else  // cas d'un drag and drop.
442 	{
443 		//g_print ("motion on drag\n");
444 		//\_______________ On recupere la position de la souris.
445 		gldi_container_update_mouse_position (CAIRO_CONTAINER (pDock));
446 
447 		//\_______________ On recalcule toutes les icones et on redessine.
448 		pPointedIcon = cairo_dock_calculate_dock_icons (pDock);
449 		gtk_widget_queue_draw (pWidget);
450 
451 		pDock->fAvoidingMouseMargin = .25;  // on peut dropper entre 2 icones ...
452 		pDock->iAvoidingMouseIconType = CAIRO_DOCK_LAUNCHER;  // ... seulement entre 2 icones du groupe "lanceurs".
453 	}
454 
455 	//\_______________ On gere le changement d'icone.
456 	gboolean bStartAnimation = FALSE;
457 	if (pPointedIcon != pLastPointedIcon)
458 	{
459 		_on_change_icon (pLastPointedIcon, pPointedIcon, pDock);
460 
461 		if (pPointedIcon != NULL && s_pIconClicked != NULL && s_pIconClicked->iGroup == pPointedIcon->iGroup && ! myDocksParam.bLockIcons && ! myDocksParam.bLockAll && ! pDock->bPreventDraggingIcons)
462 		{
463 			_cairo_dock_make_icon_glide (pPointedIcon, s_pIconClicked, pDock);
464 			bStartAnimation = TRUE;
465 		}
466 	}
467 
468 	//\_______________ On notifie tout le monde.
469 	gldi_object_notify (pDock, NOTIFICATION_MOUSE_MOVED, pDock, &bStartAnimation);
470 	if (bStartAnimation)
471 		cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
472 
473 	return FALSE;
474 }
475 
_hide_child_docks(CairoDock * pDock)476 static gboolean _hide_child_docks (CairoDock *pDock)
477 {
478 	GList* ic;
479 	Icon *icon;
480 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
481 	{
482 		icon = ic->data;
483 		if (icon->pSubDock == NULL)
484 			continue;
485 		if (gldi_container_is_visible (CAIRO_CONTAINER (icon->pSubDock)))
486 		{
487 			if (icon->pSubDock->container.bInside)
488 			{
489 				//cd_debug ("on est dans le sous-dock, donc on ne le cache pas");
490 				return FALSE;
491 			}
492 			else if (icon->pSubDock->iSidLeaveDemand == 0)  // si on sort du dock sans passer par le sous-dock, par exemple en sortant par le bas.
493 			{
494 				//cd_debug ("on cache %s par filiation", icon->cName);
495 				icon->pSubDock->fFoldingFactor = (myDocksParam.bAnimateSubDock ? 1 : 0);  /// 0
496 				gtk_widget_hide (icon->pSubDock->container.pWidget);
497 			}
498 		}
499 	}
500 	return TRUE;
501 }
502 
_on_leave_notify(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventCrossing * pEvent,CairoDock * pDock)503 static gboolean _on_leave_notify (G_GNUC_UNUSED GtkWidget* pWidget, GdkEventCrossing* pEvent, CairoDock *pDock)
504 {
505 	//g_print ("%s (bInside:%d; iState:%d; iRefCount:%d)\n", __func__, pDock->container.bInside, pDock->iInputState, pDock->iRefCount);
506 	//\_______________ On tire le dock => on ignore le signal.
507 	if (pEvent != NULL && (pEvent->state & GDK_MOD1_MASK) && (pEvent->state & GDK_BUTTON1_MASK))
508 	{
509 		return FALSE;
510 	}
511 
512 	//\_______________ On ignore les signaux errones venant d'un WM buggue (Kwin) ou meme de X (changement de bureau).
513 	//if (pEvent)
514 		//g_print ("leave event: %d;%d; %d;%d; %d; %d\n", (int)pEvent->x, (int)pEvent->y, (int)pEvent->x_root, (int)pEvent->y_root, pEvent->mode, pEvent->detail);
515 	if (pEvent && (pEvent->x != 0 ||  pEvent->y != 0 || pEvent->x_root != 0 || pEvent->y_root != 0))  // strange leave events occur (detail = GDK_NOTIFY_NONLINEAR, nil coordinates); let's ignore them!
516 	{
517 		if (pDock->container.bIsHorizontal)
518 		{
519 			pDock->container.iMouseX = pEvent->x;
520 			pDock->container.iMouseY = pEvent->y;
521 		}
522 		else
523 		{
524 			pDock->container.iMouseX = pEvent->y;
525 			pDock->container.iMouseY = pEvent->x;
526 		}
527 	}
528 	else
529 	{
530 		//g_print (" forced leave event: %d;%d\n", pDock->container.iMouseX, pDock->container.iMouseY);
531 	}
532 	if (/**pEvent && */!_mouse_is_really_outside(pDock))  // check that the mouse is really outside (the request might not come from the Window Manager, for instance if we deactivate the menu; this also works around buggy WM like KWin).
533 	{
534 		//g_print (" not really outside (%d;%d ; %d/%d)\n", pDock->container.iMouseX, pDock->container.iMouseY, pDock->iMaxDockHeight, pDock->iMinDockHeight);
535 		if (pDock->iSidTestMouseOutside == 0 && pEvent && ! pDock->bHasModalWindow)  // si l'action induit un changement de bureau, ou une appli qui bloque le focus (gksu), X envoit un signal de sortie alors qu'on est encore dans le dock, et donc n'en n'envoit plus lorsqu'on en sort reellement. On teste donc pendant qques secondes apres l'evenement. C'est ausi vrai pour l'affichage d'un menu/dialogue interactif, mais comme on envoie nous-meme un signal de sortie lorsque le menu disparait, il est inutile de le faire ici.
536 		{
537 			//g_print ("start checking mouse\n");
538 			pDock->iSidTestMouseOutside = g_timeout_add (500, (GSourceFunc)_check_mouse_outside, pDock);
539 		}
540 		return FALSE;
541 	}
542 
543 	//\_______________ On retarde la sortie.
544 	if (pEvent != NULL)  // sortie naturelle.
545 	{
546 		if (pDock->iSidLeaveDemand == 0)  // pas encore de demande de sortie.
547 		{
548 			if (pDock->iRefCount == 0)  // cas du main dock : on retarde si on pointe sur un sous-dock (pour laisser le temps au signal d'entree dans le sous-dock d'etre traite) ou si l'on a l'auto-hide.
549 			{
550 				//g_print (" leave event : %.1f;%.1f (%dx%d)\n", pEvent->x, pEvent->y, pDock->container.iWidth, pDock->container.iHeight);
551 				Icon *pPointedIcon = cairo_dock_get_pointed_icon (pDock->icons);
552 				if (pPointedIcon != NULL && pPointedIcon->pSubDock != NULL && gldi_container_is_visible (CAIRO_CONTAINER (pPointedIcon->pSubDock)))
553 				{
554 					//g_print (" on retarde la sortie du dock de %dms\n", MAX (myDocksParam.iLeaveSubDockDelay, 330));
555 					pDock->iSidLeaveDemand = g_timeout_add (MAX (myDocksParam.iLeaveSubDockDelay, 250), (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pDock);
556 					return TRUE;
557 				}
558 				else if (pDock->bAutoHide)
559 				{
560 					const int delay = 0;  // 250
561 					if (delay != 0)  /// maybe try to see if we left the dock frankly, or just by a few pixels...
562 					{
563 						//g_print (" delay the leave event by %dms\n", delay);
564 						pDock->iSidLeaveDemand = g_timeout_add (250, (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pDock);
565 						return TRUE;
566 					}
567 				}
568 			}
569 			else/** if (myDocksParam.iLeaveSubDockDelay != 0)*/  // cas d'un sous-dock : on retarde le cachage.
570 			{
571 				//g_print (" on retarde la sortie du sous-dock de %dms\n", myDocksParam.iLeaveSubDockDelay);
572 				pDock->iSidLeaveDemand = g_timeout_add (MAX (myDocksParam.iLeaveSubDockDelay, 50), (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pDock);
573 				//g_print (" -> pDock->iSidLeaveDemand = %d\n", pDock->iSidLeaveDemand);
574 				return TRUE;
575 			}
576 		}
577 		else  // deja une sortie en attente.
578 		{
579 			//g_print (" une sortie est deja programmee (%d)\n", pDock->iSidLeaveDemand);
580 			return TRUE;
581 		}
582 	}  // sinon c'est nous qui avons explicitement demande cette sortie, donc on continue.
583 
584 	if (pDock->iSidTestMouseOutside != 0)
585 	{
586 		//g_print ("stop checking mouse (leave)\n");
587 		g_source_remove (pDock->iSidTestMouseOutside);
588 		pDock->iSidTestMouseOutside = 0;
589 	}
590 
591 	//\_______________ Arrive ici, on est sorti du dock.
592 	pDock->container.bInside = FALSE;
593 	pDock->iAvoidingMouseIconType = -1;
594 	pDock->fAvoidingMouseMargin = 0;
595 
596 	//\_______________ On cache ses sous-docks.
597 	if (! _hide_child_docks (pDock))  // on quitte si l'un des sous-docks reste visible (on est entre dedans), pour rester en position "haute".
598 	{
599 		//g_print (" un des sous-docks reste visible");
600 		return TRUE;
601 	}
602 
603 	if (pDock->iRefCount != 0)  // sub-dock -> if the main icon is currently pointed, and doesn't have a dialog that would be in the way, stay visible
604 	{
605 		CairoDock *pParentDock = NULL;
606 		Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (pDock, &pParentDock);
607 		if (pPointingIcon && pParentDock)
608 		{
609 			if (pPointingIcon->bPointed && pParentDock->container.bInside && ! gldi_icon_has_dialog (pPointingIcon))
610 			{
611 				//g_print (" the main icon is currently pointed, stay visible\n");
612 				return TRUE;
613 			}
614 		}
615 	}
616 
617 	if (s_iSidShowSubDockDemand != 0 && (pDock->iRefCount == 0 || s_pSubDockShowing == pDock))  // si ce dock ou l'un des sous-docks etait programme pour se montrer, on annule.
618 	{
619 		g_source_remove (s_iSidShowSubDockDemand);
620 		s_iSidShowSubDockDemand = 0;
621 		s_pDockShowingSubDock = NULL;
622 		s_pSubDockShowing = NULL;
623 	}
624 
625 	//\_______________ If a modal window is raised, we discard the 'leave-event' to stay in the up position.
626 	if (pDock->bHasModalWindow)
627 		return TRUE;
628 
629 	//\_______________ On gere le drag d'une icone hors du dock.
630 	if (s_pIconClicked != NULL
631 	&& (CAIRO_DOCK_ICON_TYPE_IS_LAUNCHER (s_pIconClicked)
632 		|| CAIRO_DOCK_ICON_TYPE_IS_CONTAINER (s_pIconClicked)
633 		|| (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (s_pIconClicked) && s_pIconClicked->cDesktopFileName && pDock->iMaxDockHeight > 30)  // if the dock is narrow (like a panel), prevent from dragging separators outside of the dock. TODO: maybe we need a parameter in the view...
634 		|| CAIRO_DOCK_IS_DETACHABLE_APPLET (s_pIconClicked))
635 	&& s_pFlyingContainer == NULL
636 	&& ! myDocksParam.bLockIcons
637 	&& ! myDocksParam.bLockAll
638 	&& ! pDock->bPreventDraggingIcons)
639 	{
640 		cd_debug ("on a sorti %s du dock (%d;%d) / %dx%d", s_pIconClicked->cName, pDock->container.iMouseX, pDock->container.iMouseY, pDock->container.iWidth, pDock->container.iHeight);
641 
642 		//if (! _hide_child_docks (pDock))  // on quitte si on entre dans un sous-dock, pour rester en position "haute".
643 		//	return ;
644 
645 		CairoDock *pOriginDock = CAIRO_DOCK(cairo_dock_get_icon_container (s_pIconClicked));
646 		if (pOriginDock == pDock && _mouse_is_really_outside (pDock))  // ce test est la pour parer aux WM deficients mentaux comme KWin qui nous font sortir/rentrer lors d'un clic.
647 		{
648 			cd_debug (" on detache l'icone");
649 			pOriginDock->bIconIsFlyingAway = TRUE;
650 			gldi_icon_detach (s_pIconClicked);
651 			cairo_dock_stop_icon_glide (pOriginDock);
652 
653 			s_pFlyingContainer = gldi_flying_container_new (s_pIconClicked, pOriginDock);
654 			//g_print ("- s_pIconClicked <- NULL\n");
655 			s_pIconClicked = NULL;
656 			if (pDock->iRefCount > 0 || pDock->bAutoHide)  // pour garder le dock visible.
657 			{
658 				return TRUE;
659 			}
660 		}
661 	}
662 	/**else if (s_pFlyingContainer != NULL && s_pFlyingContainer->pIcon != NULL && pDock->iRefCount > 0)  // on evite les bouclages.
663 	{
664 		CairoDock *pOriginDock = gldi_dock_get (s_pFlyingContainer->pIcon->cParentDockName);
665 		if (pOriginDock == pDock)
666 			return GLDI_NOTIFICATION_INTERCEPT;
667 	}*/
668 
669 	gboolean bStartAnimation = FALSE;
670 	gldi_object_notify (pDock, NOTIFICATION_LEAVE_DOCK, pDock, &bStartAnimation);
671 	if (bStartAnimation)
672 		cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
673 
674 	return TRUE;
675 }
676 
_on_enter_notify(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventCrossing * pEvent,CairoDock * pDock)677 static gboolean _on_enter_notify (G_GNUC_UNUSED GtkWidget* pWidget, GdkEventCrossing* pEvent, CairoDock *pDock)
678 {
679 	//g_print ("%s (bIsMainDock : %d; bInside:%d; state:%d; iMagnitudeIndex:%d; input shape:%p; event:%p)\n", __func__, pDock->bIsMainDock, pDock->container.bInside, pDock->iInputState, pDock->iMagnitudeIndex, pDock->pShapeBitmap, pEvent);
680 	if (! cairo_dock_entrance_is_allowed (pDock))
681 	{
682 		cd_message ("* entree non autorisee");
683 		return FALSE;
684 	}
685 
686 	// stop les timers.
687 	if (pDock->iSidLeaveDemand != 0)
688 	{
689 		g_source_remove (pDock->iSidLeaveDemand);
690 		pDock->iSidLeaveDemand = 0;
691 	}
692 	if (s_iSidShowSubDockDemand != 0)  // gere un cas tordu mais bien reel.
693 	{
694 		g_source_remove (s_iSidShowSubDockDemand);
695 		s_iSidShowSubDockDemand = 0;
696 	}
697 	if (pDock->iSidHideBack != 0)
698 	{
699 		//g_print ("remove hide back timeout\n");
700 		g_source_remove (pDock->iSidHideBack);
701 		pDock->iSidHideBack = 0;
702 	}
703 	if (pDock->iSidTestMouseOutside != 0)
704 	{
705 		//g_print ("stop checking mouse (enter)\n");
706 		g_source_remove (pDock->iSidTestMouseOutside);
707 		pDock->iSidTestMouseOutside = 0;
708 	}
709 
710 	// input shape desactivee, le dock devient actif.
711 	if ((pDock->pShapeBitmap || pDock->pHiddenShapeBitmap) && pDock->iInputState != CAIRO_DOCK_INPUT_ACTIVE)
712 	{
713 		//g_print ("+++ input shape active on enter\n");
714 		cairo_dock_set_input_shape_active (pDock);
715 	}
716 	pDock->iInputState = CAIRO_DOCK_INPUT_ACTIVE;
717 
718 	// si on etait deja dedans, ou qu'on etait cense l'etre, on relance juste le grossissement.
719 	/**if (pDock->container.bInside || pDock->bIsHiding)
720 	{
721 		pDock->container.bInside = TRUE;
722 		cairo_dock_start_growing (pDock);
723 		if (pDock->bIsHiding || cairo_dock_is_hidden (pDock))  // on (re)monte.
724 		{
725 			cd_debug ("  on etait deja dedans\n");
726 			cairo_dock_start_showing (pDock);
727 		}
728 		return FALSE;
729 	}*/
730 
731 	gboolean bWasInside = pDock->container.bInside;
732 	pDock->container.bInside = TRUE;
733 
734 	// animation d'entree.
735 	gboolean bStartAnimation = FALSE;
736 	gldi_object_notify (pDock, NOTIFICATION_ENTER_DOCK, pDock, &bStartAnimation);
737 	if (bStartAnimation)
738 		cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
739 
740 	pDock->fDecorationsOffsetX = 0;
741 	cairo_dock_stop_quick_hide ();
742 
743 	if (s_pIconClicked != NULL)  // on pourrait le faire a chaque motion aussi.
744 	{
745 		pDock->iAvoidingMouseIconType = s_pIconClicked->iGroup;
746 		pDock->fAvoidingMouseMargin = .5;  /// inutile il me semble ...
747 	}
748 
749 	// si on rentre avec une icone volante, on la met dedans.
750 	if (s_pFlyingContainer != NULL)
751 	{
752 		Icon *pFlyingIcon = s_pFlyingContainer->pIcon;
753 		if (pDock != pFlyingIcon->pSubDock)  // on evite les boucles.
754 		{
755 			struct timeval tv;
756 			int r = gettimeofday (&tv, NULL);
757 			double t = 0.;
758 			if (r == 0)
759 				t = tv.tv_sec + tv.tv_usec * 1e-6;
760 			if (t - s_pFlyingContainer->fCreationTime > 1)  // on empeche le cas ou enlever l'icone fait augmenter le ratio du dock, et donc sa hauteur, et nous fait rentrer dedans des qu'on sort l'icone.
761 			{
762 				//g_print ("on remet l'icone volante dans un dock (dock d'origine : %s)\n", pFlyingIcon->cParentDockName);
763 				gldi_object_unref (GLDI_OBJECT(s_pFlyingContainer));  // will detach the icon
764 				gldi_icon_stop_animation (pFlyingIcon);
765 				// reinsert the icon where it was dropped, not at its original position.
766 				Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);  // get the pointed icon before we insert the icon, since the inserted icon will be the pointed one!
767 				//g_print (" pointed icon: %s\n", icon?icon->cName:"none");
768 				gldi_icon_insert_in_container (pFlyingIcon, CAIRO_CONTAINER(pDock), CAIRO_DOCK_ANIMATE_ICON);
769 				if (icon != NULL && cairo_dock_get_icon_order (icon) == cairo_dock_get_icon_order (pFlyingIcon))
770 				{
771 					cairo_dock_move_icon_after_icon (pDock, pFlyingIcon, icon);
772 				}
773 				s_pFlyingContainer = NULL;
774 				pDock->bIconIsFlyingAway = FALSE;
775 			}
776 		}
777 	}
778 
779 	// si on etait derriere, on repasse au premier plan.
780 	if (pDock->iVisibility == CAIRO_DOCK_VISI_KEEP_BELOW && pDock->bIsBelow && pDock->iRefCount == 0)
781 	{
782 		cairo_dock_pop_up (pDock);
783 	}
784 
785 	// si on etait cache (entierement ou partiellement), on montre.
786 	if ((pDock->bIsHiding || cairo_dock_is_hidden (pDock)) && pDock->iRefCount == 0)
787 	{
788 		//g_print ("  on commence a monter\n");
789 		cairo_dock_start_showing (pDock);  // on a mis a jour la zone d'input avant, sinon la fonction le ferait, ce qui serait inutile.
790 	}
791 
792 	// start growing up (do it before calculating icons, so that we don't seem to be in an anormal state, where we're inside a dock that doesn't grow).
793 	cairo_dock_start_growing (pDock);
794 
795 	// since we've just entered the dock, the pointed icon has changed from none to the current one.
796 	if (pEvent != NULL && ! bWasInside)
797 	{
798 		// update the mouse coordinates
799 		if (pDock->container.bIsHorizontal)
800 		{
801 			pDock->container.iMouseX = (int) pEvent->x;
802 			pDock->container.iMouseY = (int) pEvent->y;
803 		}
804 		else
805 		{
806 			pDock->container.iMouseX = (int) pEvent->y;
807 			pDock->container.iMouseY = (int) pEvent->x;
808 		}
809 		// then compute the icons (especially the pointed one).
810 		Icon *icon = cairo_dock_calculate_dock_icons (pDock);  // returns the pointed icon
811 		// trigger the change to trigger the animation and sub-dock popup
812 		if (icon != NULL)
813 		{
814 			_on_change_icon (NULL, icon, pDock);  // we were out of the dock, so there is no previous pointed icon.
815 		}
816 	}
817 
818 	return TRUE;
819 }
820 
821 
_on_key_release(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventKey * pKey,CairoDock * pDock)822 static gboolean _on_key_release (G_GNUC_UNUSED GtkWidget *pWidget,
823 	GdkEventKey *pKey,
824 	CairoDock *pDock)
825 {
826 	cd_debug ("on a appuye sur une touche (%d/%d)", pKey->keyval, pKey->hardware_keycode);
827 	if (pKey->type == GDK_KEY_PRESS)
828 	{
829 		gldi_object_notify (pDock, NOTIFICATION_KEY_PRESSED, pDock, pKey->keyval, pKey->state, pKey->string, pKey->hardware_keycode);
830 	}
831 	else if (pKey->type == GDK_KEY_RELEASE)
832 	{
833 		//g_print ("release : pKey->keyval = %d\n", pKey->keyval);
834 		if ((pKey->state & GDK_MOD1_MASK) && pKey->keyval == 0)  // On relache la touche ALT, typiquement apres avoir fait un ALT + clique gauche + deplacement.
835 		{
836 			if (pDock->iRefCount == 0 && pDock->iVisibility != CAIRO_DOCK_VISI_SHORTKEY)
837 				gldi_rootdock_write_gaps (pDock);
838 		}
839 	}
840 	return TRUE;
841 }
842 
843 
_double_click_delay_over(Icon * icon)844 static gboolean _double_click_delay_over (Icon *icon)
845 {
846 	CairoDock *pDock = CAIRO_DOCK (cairo_dock_get_icon_container(icon));
847 	if (pDock)
848 	{
849 		gldi_icon_stop_attention (icon);  // we consider that clicking on the icon is an acknowledge of the demand of attention.
850 		pDock->container.iMouseX = s_iFirstClickX;
851 		pDock->container.iMouseY = s_iFirstClickY;
852 		gldi_object_notify (pDock, NOTIFICATION_CLICK_ICON, icon, pDock, GDK_BUTTON1_MASK);
853 
854 		gldi_icon_start_animation (icon);
855 	}
856 	icon->iSidDoubleClickDelay = 0;
857 	return FALSE;
858 }
_check_mouse_outside(CairoDock * pDock)859 static gboolean _check_mouse_outside (CairoDock *pDock)  // ce test est principalement fait pour detecter les cas ou X nous envoit un signal leave errone alors qu'on est dedans (=> sortie refusee, bInside reste a TRUE), puis du coup ne nous en envoit pas de leave lorsqu'on quitte reellement le dock.
860 {
861 	// g_print (" %s (%d, %d, %d)\n", __func__, pDock->bIsShrinkingDown, pDock->iMagnitudeIndex, pDock->container.bInside);
862 	if (pDock->bIsShrinkingDown || pDock->iMagnitudeIndex == 0 || ! pDock->container.bInside)  // trivial cases : if the dock has already shrunk, or we're not inside any more, we can quit the loop.
863 	{
864 		pDock->iSidTestMouseOutside = 0;
865 		return FALSE;
866 	}
867 
868 	gldi_container_update_mouse_position (CAIRO_CONTAINER (pDock));
869 	// g_print (" -> (%d, %d)\n", pDock->container.iMouseX, pDock->container.iMouseY);
870 
871 	cairo_dock_calculate_dock_icons (pDock);  // pour faire retrecir le dock si on n'est pas dedans, merci X de nous faire sortir du dock alors que la souris est toujours dedans :-/
872 	return TRUE;
873 }
_on_button_press(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventButton * pButton,CairoDock * pDock)874 static gboolean _on_button_press (G_GNUC_UNUSED GtkWidget* pWidget, GdkEventButton* pButton, CairoDock *pDock)
875 {
876 	//g_print ("+ %s (%d/%d, %x)\n", __func__, pButton->type, pButton->button, pWidget);
877 	if (pDock->container.bIsHorizontal)  // utile ?
878 	{
879 		pDock->container.iMouseX = (int) pButton->x;
880 		pDock->container.iMouseY = (int) pButton->y;
881 	}
882 	else
883 	{
884 		pDock->container.iMouseX = (int) pButton->y;
885 		pDock->container.iMouseY = (int) pButton->x;
886 	}
887 
888 	Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);
889 	if (pButton->button == 1)  // clic gauche.
890 	{
891 		//g_print ("+ left click\n");
892 		switch (pButton->type)
893 		{
894 			case GDK_BUTTON_RELEASE :
895 				//g_print ("+ GDK_BUTTON_RELEASE (%d/%d sur %s/%s)\n", pButton->state, GDK_CONTROL_MASK | GDK_MOD1_MASK, icon ? icon->cName : "personne", icon ? icon->cCommand : "");  // 272 = 100010000
896 				if (pDock->container.bIgnoreNextReleaseEvent)
897 				{
898 					pDock->container.bIgnoreNextReleaseEvent = FALSE;
899 					s_pIconClicked = NULL;
900 					s_bIconDragged = FALSE;
901 					return TRUE;
902 				}
903 
904 				if ( ! (pButton->state & GDK_MOD1_MASK))
905 				{
906 					if (s_pIconClicked != NULL)
907 					{
908 						cd_debug ("activate %s (%s)", s_pIconClicked->cName, icon ? icon->cName : "none");
909 						s_pIconClicked->iAnimationState = CAIRO_DOCK_STATE_REST;  // stoppe les animations de suivi du curseur.
910 						pDock->iAvoidingMouseIconType = -1;
911 						cairo_dock_stop_icon_glide (pDock);
912 					}
913 					if (icon != NULL && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon) && icon == s_pIconClicked)  // released the button on the clicked icon => trigger the CLICK signal.
914 					{
915 						s_pIconClicked = NULL;  // il faut le faire ici au cas ou le clic induirait un dialogue bloquant qui nous ferait sortir du dock par exemple.
916 						//g_print ("+ click on '%s' (%s)\n", icon->cName, icon->cCommand);
917 						if (! s_bIconDragged)  // on ignore le drag'n'drop sur elle-meme.
918 						{
919 							if (icon->iNbDoubleClickListeners > 0)
920 							{
921 								if (icon->iSidDoubleClickDelay == 0)  // 1er release.
922 								{
923 									icon->iSidDoubleClickDelay = g_timeout_add (CD_DOUBLE_CLICK_DELAY, (GSourceFunc)_double_click_delay_over, icon);
924 									s_iFirstClickX = pDock->container.iMouseX;  // the mouse can move between the first and the second clicks; since the event is triggered when the second click occurs, the coordinates may be wrong -> we have to remember the position of the first click.
925 									s_iFirstClickY = pDock->container.iMouseY;
926 								}
927 							}
928 							else
929 							{
930 								gldi_icon_stop_attention (icon);  // we consider that clicking on the icon is an acknowledge of the demand of attention.
931 
932 								gldi_object_notify (pDock, NOTIFICATION_CLICK_ICON, icon, pDock, pButton->state);
933 
934 								gldi_icon_start_animation (icon);
935 							}
936 						}
937 					}
938 					else if (s_pIconClicked != NULL && icon != NULL && icon != s_pIconClicked && ! myDocksParam.bLockIcons && ! myDocksParam.bLockAll && ! pDock->bPreventDraggingIcons)  // released the icon on another one.
939 					{
940 						//g_print ("deplacement de %s\n", s_pIconClicked->cName);
941 						CairoDock *pOriginDock = CAIRO_DOCK (cairo_dock_get_icon_container (s_pIconClicked));
942 						if (pOriginDock != NULL && pDock != pOriginDock)
943 						{
944 							gldi_icon_detach (s_pIconClicked);
945 
946 							gldi_theme_icon_write_container_name_in_conf_file (s_pIconClicked, gldi_dock_get_name (pDock));
947 
948 							gldi_icon_insert_in_container (s_pIconClicked, CAIRO_CONTAINER(pDock), CAIRO_DOCK_ANIMATE_ICON);
949 						}
950 
951 						Icon *prev_icon, *next_icon;
952 						if (icon->fXAtRest > s_pIconClicked->fXAtRest)
953 						{
954 							prev_icon = icon;
955 							next_icon = cairo_dock_get_next_icon (pDock->icons, icon);
956 						}
957 						else
958 						{
959 							prev_icon = cairo_dock_get_previous_icon (pDock->icons, icon);
960 							next_icon = icon;
961 						}
962 						if (icon->iGroup != s_pIconClicked->iGroup
963 						&& (prev_icon == NULL || prev_icon->iGroup != s_pIconClicked->iGroup)
964 						&& (next_icon == NULL || next_icon->iGroup != s_pIconClicked->iGroup))
965 						{
966 							s_pIconClicked = NULL;
967 							return FALSE;
968 						}
969 						//g_print ("deplacement de %s\n", s_pIconClicked->cName);
970 						///if (prev_icon != NULL && prev_icon->iGroup != s_pIconClicked->iGroup)  // the previous icon is in a different group -> we'll be at the beginning of our group.
971 						///	prev_icon = NULL;  // => move to the beginning of the group/dock
972 						cairo_dock_move_icon_after_icon (pDock, s_pIconClicked, prev_icon);
973 
974 						cairo_dock_calculate_dock_icons (pDock);
975 
976 						if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (s_pIconClicked))
977 						{
978 							gldi_icon_request_animation (s_pIconClicked, "bounce", 2);
979 						}
980 						gtk_widget_queue_draw (pDock->container.pWidget);
981 					}
982 
983 					if (s_pFlyingContainer != NULL)  // the user released the flying icon -> detach/destroy it, or insert it
984 					{
985 						cd_debug ("on relache l'icone volante");
986 						if (pDock->container.bInside)
987 						{
988 							//g_print ("  on la remet dans son dock d'origine\n");
989 							Icon *pFlyingIcon = s_pFlyingContainer->pIcon;
990 							gldi_object_unref (GLDI_OBJECT(s_pFlyingContainer));
991 							cairo_dock_stop_marking_icon_as_following_mouse (pFlyingIcon);
992 							// reinsert the icon where it was dropped, not at its original position.
993 							Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);  // get the pointed icon before we insert the icon, since the inserted icon will be the pointed one!
994 							gldi_icon_insert_in_container (pFlyingIcon, CAIRO_CONTAINER(pDock), CAIRO_DOCK_ANIMATE_ICON);
995 							if (icon != NULL && cairo_dock_get_icon_order (icon) == cairo_dock_get_icon_order (pFlyingIcon))
996 							{
997 								cairo_dock_move_icon_after_icon (pDock, pFlyingIcon, icon);
998 							}
999 						}
1000 						else
1001 						{
1002 							gldi_flying_container_terminate (s_pFlyingContainer);  // supprime ou detache l'icone, l'animation se terminera toute seule.
1003 						}
1004 						s_pFlyingContainer = NULL;
1005 						pDock->bIconIsFlyingAway = FALSE;
1006 						cairo_dock_stop_icon_glide (pDock);
1007 					}
1008 					/// a implementer ...
1009 					///gldi_object_notify (CAIRO_CONTAINER (pDock), CAIRO_DOCK_RELEASE_ICON, icon, pDock);
1010 				}
1011 				else
1012 				{
1013 					if (pDock->iRefCount == 0 && pDock->iVisibility != CAIRO_DOCK_VISI_SHORTKEY)
1014 						gldi_rootdock_write_gaps (pDock);
1015 				}
1016 				//g_print ("- apres clic : s_pIconClicked <- NULL\n");
1017 				s_pIconClicked = NULL;
1018 				s_bIconDragged = FALSE;
1019 			break ;
1020 
1021 			case GDK_BUTTON_PRESS :
1022 				if ( ! (pButton->state & GDK_MOD1_MASK))
1023 				{
1024 					//g_print ("+ clic sur %s (%.2f)!\n", icon ? icon->cName : "rien", icon ? icon->fInsertRemoveFactor : 0.);
1025 					s_iClickX = pButton->x;
1026 					s_iClickY = pButton->y;
1027 					if (icon && ! cairo_dock_icon_is_being_removed (icon) && ! CAIRO_DOCK_IS_AUTOMATIC_SEPARATOR (icon))
1028 					{
1029 						s_pIconClicked = icon;  // on ne definit pas l'animation FOLLOW_MOUSE ici , on le fera apres le 1er mouvement, pour eviter que l'icone soit dessinee comme tel quand on clique dessus alors que le dock est en train de jouer une animation (ca provoque un flash desagreable).
1030 						cd_debug ("clicked on %s", icon->cName);
1031 					}
1032 					else
1033 						s_pIconClicked = NULL;
1034 				}
1035 			break ;
1036 
1037 			case GDK_2BUTTON_PRESS :
1038 				if (icon && ! cairo_dock_icon_is_being_removed (icon))
1039 				{
1040 					if (icon->iSidDoubleClickDelay != 0)
1041 					{
1042 						g_source_remove (icon->iSidDoubleClickDelay);
1043 						icon->iSidDoubleClickDelay = 0;
1044 					}
1045 					gldi_object_notify (pDock, NOTIFICATION_DOUBLE_CLICK_ICON, icon, pDock);
1046 					if (icon->iNbDoubleClickListeners > 0)
1047 						pDock->container.bIgnoreNextReleaseEvent = TRUE;
1048 				}
1049 			break ;
1050 
1051 			default :
1052 			break ;
1053 		}
1054 	}
1055 	else if (pButton->button == 3 && pButton->type == GDK_BUTTON_PRESS)  // clique droit.
1056 	{
1057 		GtkWidget *menu = gldi_container_build_menu (CAIRO_CONTAINER (pDock), icon);  // genere un CAIRO_DOCK_BUILD_CONTAINER_MENU et CAIRO_DOCK_BUILD_ICON_MENU.
1058 
1059 		gldi_menu_popup (menu);
1060 	}
1061 	else if (pButton->button == 2 && pButton->type == GDK_BUTTON_PRESS)  // clique milieu.
1062 	{
1063 		if (icon && ! cairo_dock_icon_is_being_removed (icon))
1064 		{
1065 			gldi_object_notify (pDock, NOTIFICATION_MIDDLE_CLICK_ICON, icon, pDock);
1066 		}
1067 	}
1068 
1069 	return FALSE;
1070 }
1071 
1072 
_on_scroll(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventScroll * pScroll,CairoDock * pDock)1073 static gboolean _on_scroll (G_GNUC_UNUSED GtkWidget* pWidget, GdkEventScroll* pScroll, CairoDock *pDock)
1074 {
1075 	if (pScroll->direction != GDK_SCROLL_UP && pScroll->direction != GDK_SCROLL_DOWN)  // on degage les scrolls horizontaux.
1076 	{
1077 		return FALSE;
1078 	}
1079 	Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);  // can be NULL
1080 	gldi_object_notify (pDock, NOTIFICATION_SCROLL_ICON, icon, pDock, pScroll->direction);
1081 
1082 	return FALSE;
1083 }
1084 
1085 
_on_configure(GtkWidget * pWidget,GdkEventConfigure * pEvent,CairoDock * pDock)1086 static gboolean _on_configure (GtkWidget* pWidget, GdkEventConfigure* pEvent, CairoDock *pDock)
1087 {
1088 	//g_print ("%s (%p, main dock : %d) : (%d;%d) (%dx%d)\n", __func__, pDock, pDock->bIsMainDock, pEvent->x, pEvent->y, pEvent->width, pEvent->height);
1089 	// set the new actual size of the container
1090 	gint iNewWidth, iNewHeight, iNewX, iNewY;
1091 	if (pDock->container.bIsHorizontal)
1092 	{
1093 		iNewWidth = pEvent->width;
1094 		iNewHeight = pEvent->height;
1095 
1096 		iNewX = pEvent->x;
1097 		iNewY = pEvent->y;
1098 	}
1099 	else
1100 	{
1101 		iNewWidth = pEvent->height;
1102 		iNewHeight = pEvent->width;
1103 
1104 		iNewX = pEvent->y;
1105 		iNewY = pEvent->x;
1106 	}
1107 
1108 	gboolean bSizeUpdated = (iNewWidth != pDock->container.iWidth || iNewHeight != pDock->container.iHeight);
1109 	///gboolean bIsNowSized = (pDock->container.iWidth == 1 && pDock->container.iHeight == 1 && bSizeUpdated);
1110 	gboolean bPositionUpdated = (pDock->container.iWindowPositionX != iNewX || pDock->container.iWindowPositionY != iNewY);
1111 	pDock->container.iWidth = iNewWidth;
1112 	pDock->container.iHeight = iNewHeight;
1113 	pDock->container.iWindowPositionX = iNewX;
1114 	pDock->container.iWindowPositionY = iNewY;
1115 
1116 	if (pDock->container.iWidth == 1 && pDock->container.iHeight == 1)  // the X window has not yet reached its size.
1117 	{
1118 		return FALSE;
1119 	}
1120 
1121 	// if the size has changed, also update everything that depends on it.
1122 	if (bSizeUpdated)  // changement de taille
1123 	{
1124 		// update mouse relative position inside the window
1125 		gldi_container_update_mouse_position (CAIRO_CONTAINER (pDock));
1126 		if (pDock->container.iMouseX < 0 || pDock->container.iMouseX > pDock->container.iWidth)  // utile ?
1127 			pDock->container.iMouseX = 0;
1128 
1129 		// update the input shape (it has been calculated in the function that made the resize)
1130 		cairo_dock_update_input_shape (pDock);
1131 		switch (pDock->iInputState)  // update the input zone
1132 		{
1133 			case CAIRO_DOCK_INPUT_ACTIVE:
1134 				cairo_dock_set_input_shape_active (pDock);
1135 			break;
1136 			case CAIRO_DOCK_INPUT_AT_REST:
1137 				cairo_dock_set_input_shape_at_rest (pDock);
1138 			break;
1139 			case CAIRO_DOCK_INPUT_HIDDEN:
1140 				cairo_dock_set_input_shape_hidden (pDock);
1141 			break;
1142 			default:
1143 			break;
1144 		}
1145 
1146 		// update the GL context
1147 		if (g_bUseOpenGL)
1148 		{
1149 			if (! gldi_gl_container_make_current (CAIRO_CONTAINER (pDock)))
1150 				return FALSE;
1151 
1152 			gldi_gl_container_set_ortho_view (CAIRO_CONTAINER (pDock));
1153 
1154 			glClearAccum (0., 0., 0., 0.);
1155 			glClear (GL_ACCUM_BUFFER_BIT);
1156 
1157 			if (pDock->iRedirectedTexture != 0)
1158 			{
1159 				_cairo_dock_delete_texture (pDock->iRedirectedTexture);
1160 				pDock->iRedirectedTexture = cairo_dock_create_texture_from_raw_data (NULL, pEvent->width, pEvent->height);
1161 			}
1162 		}
1163 
1164 		cairo_dock_calculate_dock_icons (pDock);
1165 		//g_print ("configure size %s\n", pDock->cDockName);
1166 		cairo_dock_trigger_set_WM_icons_geometry (pDock);  // changement de position ou de taille du dock => on replace les icones.
1167 
1168 		gldi_dialogs_replace_all ();
1169 
1170 		if (/**bIsNowSized*/bSizeUpdated && g_bUseOpenGL)  // in OpenGL, the context is linked to the window; now that the window has a correct size, the context is ready -> draw things that couldn't be drawn until now.
1171 		{
1172 			Icon *icon;
1173 			GList *ic;
1174 			for (ic = pDock->icons; ic != NULL; ic = ic->next)
1175 			{
1176 				icon = ic->data;
1177 				gboolean bDamaged = icon->bDamaged;  // if bNeedApplyBackground is also TRUE, applying the background will remove the 'damage' flag.
1178 				if (icon->bNeedApplyBackground)  // if both are TRUE, we need to do both (for instance, the data-renderer might not redraw the icon (progressbar)). draw the bg first so that we don't draw it twice.
1179 				{
1180 					icon->bNeedApplyBackground = FALSE;  // set to FALSE, if it doesn't work here, it will probably never do.
1181 					cairo_dock_apply_icon_background_opengl (icon);
1182 				}
1183 				if (bDamaged)
1184 				{
1185 					//g_print ("This icon %s is damaged (%d)\n", icon->cName, icon->iSubdockViewType);
1186 					icon->bDamaged = FALSE;
1187 					if (cairo_dock_get_icon_data_renderer (icon) != NULL)
1188 					{
1189 						cairo_dock_refresh_data_renderer (icon, CAIRO_CONTAINER (pDock));
1190 					}
1191 					else if (icon->iSubdockViewType != 0
1192 					|| (icon->cClass != NULL && ! myIndicatorsParam.bUseClassIndic && (CAIRO_DOCK_ICON_TYPE_IS_CLASS_CONTAINER (icon) || GLDI_OBJECT_IS_LAUNCHER_ICON (icon))))
1193 					{
1194 						cairo_dock_draw_subdock_content_on_icon (icon, pDock);
1195 					}
1196 					else if (CAIRO_DOCK_IS_APPLET (icon))
1197 					{
1198 						gldi_object_reload (GLDI_OBJECT(icon->pModuleInstance), FALSE);  // easy but safe way to redraw the icon properly.
1199 					}
1200 					else  // if we don't know how the icon should be drawn, just reload it.
1201 					{
1202 						cairo_dock_load_icon_image (icon, CAIRO_CONTAINER (pDock));
1203 					}
1204 					if (pDock->iRefCount != 0)  // now that the icon image is correct, redraw the pointing icon if needed
1205 						cairo_dock_trigger_redraw_subdock_content (pDock);
1206 				}
1207 			}
1208 		}
1209 	}
1210 	else if (bPositionUpdated)  // changement de position.
1211 	{
1212 		//g_print ("configure x,y\n");
1213 		cairo_dock_trigger_set_WM_icons_geometry (pDock);  // changement de position de la fenetre du dock => on replace les icones.
1214 
1215 		gldi_dialogs_replace_all ();
1216 	}
1217 
1218 	if (pDock->iRefCount == 0 && (bSizeUpdated || bPositionUpdated))
1219 	{
1220 		if (pDock->iVisibility == CAIRO_DOCK_VISI_AUTO_HIDE_ON_OVERLAP)
1221 		{
1222 			GldiWindowActor *pActiveAppli = gldi_windows_get_active ();
1223 			if (_gldi_window_is_on_our_way (pActiveAppli, pDock))  // la fenetre active nous gene.
1224 			{
1225 				if (!cairo_dock_is_temporary_hidden (pDock))
1226 					cairo_dock_activate_temporary_auto_hide (pDock);
1227 			}
1228 			else
1229 			{
1230 				if (cairo_dock_is_temporary_hidden (pDock))
1231 					cairo_dock_deactivate_temporary_auto_hide (pDock);
1232 			}
1233 		}
1234 		else if (pDock->iVisibility == CAIRO_DOCK_VISI_AUTO_HIDE_ON_OVERLAP_ANY)
1235 		{
1236 			if (gldi_dock_search_overlapping_window (pDock) != NULL)
1237 			{
1238 				if (!cairo_dock_is_temporary_hidden (pDock))
1239 					cairo_dock_activate_temporary_auto_hide (pDock);
1240 			}
1241 			else
1242 			{
1243 				if (cairo_dock_is_temporary_hidden (pDock))
1244 					cairo_dock_deactivate_temporary_auto_hide (pDock);
1245 			}
1246 		}
1247 	}
1248 
1249 	gtk_widget_queue_draw (pWidget);
1250 
1251 	return FALSE;
1252 }
1253 
1254 
1255 
1256 static gboolean s_bWaitForData = FALSE;
1257 static gboolean s_bCouldDrop = FALSE;
1258 
_on_drag_data_received(G_GNUC_UNUSED GtkWidget * pWidget,GdkDragContext * dc,gint x,gint y,GtkSelectionData * selection_data,G_GNUC_UNUSED guint info,guint time,CairoDock * pDock)1259 void _on_drag_data_received (G_GNUC_UNUSED GtkWidget *pWidget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, G_GNUC_UNUSED guint info, guint time, CairoDock *pDock)
1260 {
1261 	cd_debug ("%s (%dx%d, %d, %d)", __func__, x, y, time, pDock->container.bInside);
1262 	if (cairo_dock_is_hidden (pDock))  // X ne semble pas tenir compte de la zone d'input pour dropper les trucs...
1263 		return ;
1264 	//\_________________ On recupere l'URI.
1265 	gchar *cReceivedData = (gchar *)gtk_selection_data_get_data (selection_data);  // the data are actually 'const guchar*', but since we only allowed text and urls, it will be a string
1266 	g_return_if_fail (cReceivedData != NULL);
1267 	int length = strlen (cReceivedData);
1268 	if (cReceivedData[length-1] == '\n')
1269 		cReceivedData[--length] = '\0';  // on vire le retour chariot final.
1270 	if (cReceivedData[length-1] == '\r')
1271 		cReceivedData[--length] = '\0';
1272 
1273 	if (s_bWaitForData)
1274 	{
1275 		s_bWaitForData = FALSE;
1276 		gdk_drag_status (dc, GDK_ACTION_COPY, time);
1277 		cd_debug ("drag info : <%s>", cReceivedData);
1278 		pDock->iAvoidingMouseIconType = CAIRO_DOCK_LAUNCHER;
1279 		if (g_str_has_suffix (cReceivedData, ".desktop")/** || g_str_has_suffix (cReceivedData, ".sh")*/)
1280 			pDock->fAvoidingMouseMargin = .5;  // on ne sera jamais dessus.
1281 		else
1282 			pDock->fAvoidingMouseMargin = .25;
1283 		return ;
1284 	}
1285 
1286 	//\_________________ On arrete l'animation.
1287 	//cairo_dock_stop_marking_icons (pDock);
1288 	pDock->iAvoidingMouseIconType = -1;
1289 	pDock->fAvoidingMouseMargin = 0;
1290 
1291 	//\_________________ On arrete le timer.
1292 	if (s_iSidActionOnDragHover != 0)
1293 	{
1294 		//cd_debug ("on annule la demande de montrage d'appli");
1295 		g_source_remove (s_iSidActionOnDragHover);
1296 		s_iSidActionOnDragHover = 0;
1297 	}
1298 
1299 	//\_________________ On calcule la position a laquelle on l'a lache.
1300 	cd_debug (">>> cReceivedData : '%s' (%d/%d)", cReceivedData, s_bCouldDrop, pDock->bCanDrop);
1301 	/* icon => drop on icon
1302 	no icon => if order undefined: drop on dock; else: drop between 2 icons.*/
1303 	Icon *pPointedIcon = NULL;
1304 	double fOrder;
1305 	if (s_bCouldDrop)  // can drop on the dock
1306 	{
1307 		cd_debug ("drop between icons");
1308 
1309 		pPointedIcon = NULL;
1310 		fOrder = 0;
1311 
1312 		// try to guess where we dropped.
1313 		int iDropX = (pDock->container.bIsHorizontal ? x : y);
1314 		Icon *pNeighboorIcon;
1315 		Icon *icon = NULL;
1316 		GList *ic;
1317 		for (ic = pDock->icons; ic != NULL; ic = ic->next)
1318 		{
1319 			icon = ic->data;
1320 			if (icon->bPointed)
1321 			{
1322 				if (iDropX < icon->fDrawX + icon->fWidth * icon->fScale/2)  // on the left side of the icon
1323 				{
1324 					pNeighboorIcon = (ic->prev != NULL ? ic->prev->data : NULL);
1325 					fOrder = (pNeighboorIcon != NULL ? (icon->fOrder + pNeighboorIcon->fOrder) / 2 : icon->fOrder - 1);
1326 				}
1327 				else  // on the right side of the icon
1328 				{
1329 					pNeighboorIcon = (ic->next != NULL ? ic->next->data : NULL);
1330 					fOrder = (pNeighboorIcon != NULL ? (icon->fOrder + pNeighboorIcon->fOrder) / 2 : icon->fOrder + 1);
1331 				}
1332 				break;
1333 			}
1334 		}
1335 		if (myDocksParam.bLockAll)  // locked, can't add anything.
1336 		{
1337 			gldi_dialog_show_temporary_with_default_icon (_("Sorry but the dock is locked"), icon, CAIRO_CONTAINER (pDock), 5000);
1338 			gtk_drag_finish (dc, FALSE, FALSE, time);
1339 			return ;
1340 		}
1341 	}
1342 	else  // drop on an icon or nowhere.
1343 	{
1344 		pPointedIcon = cairo_dock_get_pointed_icon (pDock->icons);
1345 		fOrder = CAIRO_DOCK_LAST_ORDER;
1346 		if (pPointedIcon == NULL && ! g_str_has_suffix (cReceivedData, ".desktop"))  // no icon => abort, but .desktop are always added
1347 		{
1348 			cd_debug ("drop nowhere");
1349 			gtk_drag_finish (dc, FALSE, FALSE, time);
1350 			return;
1351 		}
1352 	}
1353 	cd_debug ("drop on %s (%.2f)", pPointedIcon?pPointedIcon->cName:"dock", fOrder);
1354 
1355 	gldi_container_notify_drop_data (CAIRO_CONTAINER (pDock), cReceivedData, pPointedIcon, fOrder);
1356 
1357 	gtk_drag_finish (dc, TRUE, FALSE, time);
1358 }
1359 
1360 /*static gboolean _on_drag_drop (GtkWidget *pWidget, GdkDragContext *dc, gint x, gint y, guint time, G_GNUC_UNUSED CairoDock *pDock)
1361 {
1362 	cd_message ("%s (%dx%d, %d)", __func__, x, y, time);
1363 	GdkAtom target = gtk_drag_dest_find_target (pWidget, dc, NULL);
1364 	gtk_drag_get_data (pWidget, dc, target, time);
1365 	return TRUE;  // in a drop zone.
1366 }*/
1367 
1368 
_on_drag_motion(GtkWidget * pWidget,GdkDragContext * dc,gint x,gint y,guint time,CairoDock * pDock)1369 static gboolean _on_drag_motion (GtkWidget *pWidget, GdkDragContext *dc, gint x, gint y, guint time, CairoDock *pDock)
1370 {
1371 	cd_debug ("%s (%d;%d, %d)", __func__, x, y, time);
1372 
1373 	//\_________________ On simule les evenements souris habituels.
1374 	if (! pDock->bIsDragging)
1375 	{
1376 		cd_debug ("start dragging");
1377 		pDock->bIsDragging = TRUE;
1378 
1379 		/*GdkAtom gdkAtom = gdk_drag_get_selection (dc);
1380 		Atom xAtom = gdk_x11_atom_to_xatom (gdkAtom);
1381 		Window Xid = GDK_WINDOW_XID (dc->source_window);
1382 		cd_debug (" <%s>", cairo_dock_get_property_name_on_xwindow (Xid, xAtom));*/
1383 
1384 		gboolean bStartAnimation = FALSE;
1385 		gldi_object_notify (pDock, NOTIFICATION_START_DRAG_DATA, pDock, &bStartAnimation);
1386 		if (bStartAnimation)
1387 			cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
1388 
1389 		/*pDock->iAvoidingMouseIconType = -1;
1390 
1391 		GdkAtom target = gtk_drag_dest_find_target (pWidget, dc, NULL);
1392 		if (target == GDK_NONE)
1393 			gdk_drag_status (dc, 0, time);
1394 		else
1395 		{
1396 			gtk_drag_get_data (pWidget, dc, target, time);
1397 			s_bWaitForData = TRUE;
1398 			cd_debug ("get-data envoye\n");
1399 		}*/
1400 
1401 		_on_enter_notify (pWidget, NULL, pDock);  // ne sera effectif que la 1ere fois a chaque entree dans un dock.
1402 	}
1403 	else
1404 	{
1405 		//g_print ("move dragging\n");
1406 		_on_motion_notify (pWidget, NULL, pDock);
1407 	}
1408 
1409 	int X, Y;
1410 	if (pDock->container.bIsHorizontal)
1411 	{
1412 		X = x - pDock->container.iWidth/2;
1413 		Y = y;
1414 	}
1415 	else
1416 	{
1417 		Y = x;
1418 		X = y - pDock->container.iWidth/2;
1419 	}
1420 	if (pDock->iInputState == CAIRO_DOCK_INPUT_AT_REST)
1421 	{
1422 		int w = pDock->iMinDockWidth;
1423 		int h = pDock->iMinDockHeight;
1424 
1425 		if (X <= -w/2 || X >= w/2)
1426 			return FALSE;  // on n'accepte pas le drop.
1427 		if (pDock->container.bDirectionUp)
1428 		{
1429 			if (Y < pDock->container.iHeight - h || Y >= pDock->container.iHeight)
1430 				return FALSE;  // on n'accepte pas le drop.
1431 		}
1432 		else
1433 		{
1434 			if (Y < 0 || Y > h)
1435 				return FALSE;  // on n'accepte pas le drop.
1436 		}
1437 	}
1438 	else if (pDock->iInputState == CAIRO_DOCK_INPUT_HIDDEN)
1439 	{
1440 		return FALSE;  // on n'accepte pas le drop.
1441 	}
1442 
1443 	//g_print ("take the drop\n");
1444 	gdk_drag_status (dc, GDK_ACTION_COPY, time);
1445 	return TRUE;  // on accepte le drop.
1446 }
1447 
_on_drag_leave(GtkWidget * pWidget,G_GNUC_UNUSED GdkDragContext * dc,G_GNUC_UNUSED guint time,CairoDock * pDock)1448 void _on_drag_leave (GtkWidget *pWidget, G_GNUC_UNUSED GdkDragContext *dc, G_GNUC_UNUSED guint time, CairoDock *pDock)
1449 {
1450 	//g_print ("stop dragging 1\n");
1451 	Icon *icon = cairo_dock_get_pointed_icon (pDock->icons);
1452 	if ((icon && icon->pSubDock) || pDock->iRefCount > 0)  // on retarde l'evenement, car il arrive avant le leave-event, et donc le sous-dock se cache avant qu'on puisse y entrer.
1453 	{
1454 		cd_debug (">>> on attend...");
1455 		while (gtk_events_pending ())  // on laisse le temps au signal d'entree dans le sous-dock d'etre traite, de facon a avoir un start-dragging avant de quitter cette fonction.
1456 			gtk_main_iteration ();
1457 		cd_debug (">>> pDock->container.bInside : %d", pDock->container.bInside);
1458 	}
1459 	//g_print ("stop dragging 2\n");
1460 	s_bWaitForData = FALSE;
1461 	pDock->bIsDragging = FALSE;
1462 	s_bCouldDrop = pDock->bCanDrop;
1463 	pDock->bCanDrop = FALSE;
1464 	//cairo_dock_stop_marking_icons (pDock);
1465 	pDock->iAvoidingMouseIconType = -1;
1466 
1467 	// emit a leave-event signal, since we don't get one if we leave the window too quickly (!)
1468 	if (pDock->iSidLeaveDemand == 0)
1469 	{
1470 		pDock->iSidLeaveDemand = g_timeout_add (MAX (myDocksParam.iLeaveSubDockDelay, 330), (GSourceFunc) _emit_leave_signal_delayed, (gpointer) pDock);  // emit with a delay, so that we can leave and enter the dock for a few ms without making it hide.
1471 	}
1472 	// emulate a motion event so that the mouse position is up-to-date (which is not the case if we leave the window too quickly).
1473 	_on_motion_notify (pWidget, NULL, pDock);
1474 }
1475 
1476 
1477   ///////////////////////
1478  /// CONTAINER IFACE ///
1479 ///////////////////////
1480 
_cairo_dock_grow_up(CairoDock * pDock)1481 static gboolean _cairo_dock_grow_up (CairoDock *pDock)
1482 {
1483 	//g_print ("%s (%d ; %2f ; bInside:%d)\n", __func__, pDock->iMagnitudeIndex, pDock->fFoldingFactor, pDock->container.bInside);
1484 
1485 	pDock->iMagnitudeIndex += myBackendsParam.iGrowUpInterval;
1486 	if (pDock->iMagnitudeIndex > CAIRO_DOCK_NB_MAX_ITERATIONS)
1487 		pDock->iMagnitudeIndex = CAIRO_DOCK_NB_MAX_ITERATIONS;
1488 
1489 	if (pDock->fFoldingFactor != 0)
1490 	{
1491 		int iAnimationDeltaT = cairo_dock_get_animation_delta_t (pDock);
1492 		pDock->fFoldingFactor -= (double) iAnimationDeltaT / myBackendsParam.iUnfoldingDuration;
1493 		if (pDock->fFoldingFactor < 0)
1494 			pDock->fFoldingFactor = 0;
1495 	}
1496 
1497 	gldi_container_update_mouse_position (CAIRO_CONTAINER (pDock));
1498 
1499 	Icon *pLastPointedIcon = cairo_dock_get_pointed_icon (pDock->icons);
1500 	Icon *pPointedIcon = cairo_dock_calculate_dock_icons (pDock);
1501 	if (! pDock->bIsGrowingUp)
1502 		return FALSE;
1503 
1504 	if (pLastPointedIcon != pPointedIcon && pDock->container.bInside)
1505 		_on_change_icon (pLastPointedIcon, pPointedIcon, pDock);  /// probablement inutile...
1506 
1507 	if (pDock->iMagnitudeIndex == CAIRO_DOCK_NB_MAX_ITERATIONS && pDock->fFoldingFactor == 0)  // fin de grossissement et de depliage.
1508 	{
1509 		gldi_dialogs_replace_all ();
1510 		return FALSE;
1511 	}
1512 	else
1513 		return TRUE;
1514 }
1515 
_hide_parent_dock(CairoDock * pDock)1516 static void _hide_parent_dock (CairoDock *pDock)
1517 {
1518 	CairoDock *pParentDock = NULL;
1519 	Icon *pIcon = cairo_dock_search_icon_pointing_on_dock (pDock, &pParentDock);
1520 	if (pIcon && pParentDock)
1521 	{
1522 		if (pParentDock->iRefCount == 0)
1523 		{
1524 			cairo_dock_emit_leave_signal (CAIRO_CONTAINER (pParentDock));
1525 		}
1526 		else
1527 		{
1528 			//cd_message ("on cache %s par parente", cDockName);
1529 			gtk_widget_hide (pParentDock->container.pWidget);
1530 			_hide_parent_dock (pParentDock);
1531 		}
1532 	}
1533 }
1534 
_cairo_dock_shrink_down(CairoDock * pDock)1535 static gboolean _cairo_dock_shrink_down (CairoDock *pDock)
1536 {
1537 	//g_print ("%s (%d, %f, %f)\n", __func__, pDock->iMagnitudeIndex, pDock->fFoldingFactor, pDock->fDecorationsOffsetX);
1538 	//\_________________ On fait decroitre la magnitude du dock.
1539 	pDock->iMagnitudeIndex -= myBackendsParam.iShrinkDownInterval;
1540 	if (pDock->iMagnitudeIndex < 0)
1541 		pDock->iMagnitudeIndex = 0;
1542 
1543 	//\_________________ On replie le dock.
1544 	if (pDock->fFoldingFactor != 0 && pDock->fFoldingFactor != 1)
1545 	{
1546 		int iAnimationDeltaT = cairo_dock_get_animation_delta_t (pDock);
1547 		pDock->fFoldingFactor += (double) iAnimationDeltaT / myBackendsParam.iUnfoldingDuration;
1548 		if (pDock->fFoldingFactor > 1)
1549 			pDock->fFoldingFactor = 1;
1550 	}
1551 
1552 	//\_________________ On remet les decorations a l'equilibre.
1553 	pDock->fDecorationsOffsetX *= .8;
1554 	if (fabs (pDock->fDecorationsOffsetX) < 3)
1555 		pDock->fDecorationsOffsetX = 0.;
1556 
1557 	//\_________________ On recupere la position de la souris manuellement (car a priori on est hors du dock).
1558 	gldi_container_update_mouse_position (CAIRO_CONTAINER (pDock));  // ce n'est pas le motion_notify qui va nous donner des coordonnees en dehors du dock, et donc le fait d'etre dedans va nous faire interrompre le shrink_down et re-grossir, du coup il faut le faire ici. L'inconvenient, c'est que quand on sort par les cotes, il n'y a soudain plus d'icone pointee, et donc le dock devient tout plat subitement au lieu de le faire doucement. Heureusement j'ai trouve une astuce. ^_^
1559 
1560 	//\_________________ On recalcule les icones.
1561 	///if (iPrevMagnitudeIndex != 0)
1562 	{
1563 		cairo_dock_calculate_dock_icons (pDock);
1564 		if (! pDock->bIsShrinkingDown)
1565 			return FALSE;
1566 	}
1567 
1568 	if (pDock->iMagnitudeIndex == 0 && (pDock->fFoldingFactor == 0 || pDock->fFoldingFactor == 1))  // on est arrive en bas.
1569 	{
1570 		//g_print ("equilibre atteint (%d)\n", pDock->container.bInside);
1571 		if (! pDock->container.bInside)  // on peut etre hors des icones sans etre hors de la fenetre.
1572 		{
1573 			//g_print ("rideau !\n");
1574 
1575 			//\__________________ On repasse derriere si on etait devant.
1576 			if (pDock->iVisibility == CAIRO_DOCK_VISI_KEEP_BELOW && ! pDock->bIsBelow)
1577 				cairo_dock_pop_down (pDock);
1578 
1579 			//\__________________ On se redimensionne en taille normale.
1580 			if (! pDock->bAutoHide && pDock->iRefCount == 0/** && ! pDock->bMenuVisible*/)  // fin de shrink sans auto-hide => taille normale.
1581 			{
1582 				//g_print ("taille normale (%x; %d)\n", pDock->pShapeBitmap , pDock->iInputState);
1583 				if (pDock->pShapeBitmap && pDock->iInputState != CAIRO_DOCK_INPUT_AT_REST)
1584 				{
1585 					//g_print ("+++ input shape at rest on end shrinking\n");
1586 					cairo_dock_set_input_shape_at_rest (pDock);
1587 					pDock->iInputState = CAIRO_DOCK_INPUT_AT_REST;
1588 				}
1589 			}
1590 
1591 			//\__________________ On se cache si sous-dock.
1592 			if (pDock->iRefCount > 0)
1593 			{
1594 				//g_print ("on cache ce sous-dock en sortant par lui\n");
1595 				gtk_widget_hide (pDock->container.pWidget);
1596 				_hide_parent_dock (pDock);
1597 			}
1598 			///cairo_dock_hide_after_shortcut ();
1599 			if (pDock->iVisibility == CAIRO_DOCK_VISI_SHORTKEY)  // hide at the end of the shrink animation
1600 			{
1601 				gtk_widget_hide (pDock->container.pWidget);
1602 			}
1603 		}
1604 		else
1605 		{
1606 			cairo_dock_calculate_dock_icons (pDock);  // relance le grossissement si on est dedans.
1607 		}
1608 		if (!pDock->bIsGrowingUp)
1609 			gldi_dialogs_replace_all ();
1610 		return (!pDock->bIsGrowingUp && (pDock->fDecorationsOffsetX != 0 || (pDock->fFoldingFactor != 0 && pDock->fFoldingFactor != 1)));
1611 	}
1612 	else
1613 	{
1614 		return (!pDock->bIsGrowingUp);
1615 	}
1616 }
1617 
_cairo_dock_hide(CairoDock * pDock)1618 static gboolean _cairo_dock_hide (CairoDock *pDock)
1619 {
1620 	//g_print ("%s (%d, %.2f, %.2f)\n", __func__, pDock->iMagnitudeIndex, pDock->fHideOffset, pDock->fPostHideOffset);
1621 
1622 	if (pDock->fHideOffset < 1)  // the hiding animation is running.
1623 	{
1624 		pDock->fHideOffset += 1./myBackendsParam.iHideNbSteps;
1625 		if (pDock->fHideOffset > .99)  // fin d'anim.
1626 		{
1627 			pDock->fHideOffset = 1;
1628 
1629 			//g_print ("on arrete le cachage\n");
1630 			gboolean bVisibleIconsPresent = FALSE;
1631 			Icon *pIcon;
1632 			GList *ic;
1633 			for (ic = pDock->icons; ic != NULL; ic = ic->next)
1634 			{
1635 				pIcon = ic->data;
1636 				if (pIcon->fInsertRemoveFactor != 0)  // on accelere l'animation d'apparition/disparition.
1637 				{
1638 					if (pIcon->fInsertRemoveFactor > 0)
1639 						pIcon->fInsertRemoveFactor = 0.05;
1640 					else
1641 						pIcon->fInsertRemoveFactor = - 0.05;
1642 				}
1643 
1644 				if (! pIcon->bIsDemandingAttention && ! pIcon->bAlwaysVisible && ! pIcon->bIsLaunching)
1645 					gldi_icon_stop_animation (pIcon);  // s'il y'a une autre animation en cours, on l'arrete.
1646 				else
1647 					bVisibleIconsPresent = TRUE;
1648 			}
1649 
1650 			pDock->pRenderer->calculate_icons (pDock);
1651 			///pDock->fFoldingFactor = (myBackendsParam.bAnimateOnAutoHide ? .99 : 0.);  // on arme le depliage.
1652 			cairo_dock_allow_entrance (pDock);
1653 
1654 			gldi_dialogs_replace_all ();
1655 
1656 			if (bVisibleIconsPresent)  // il y'a des icones a montrer progressivement, on reste dans la boucle.
1657 			{
1658 				pDock->fPostHideOffset = 0.05;
1659 				return TRUE;
1660 			}
1661 			else
1662 			{
1663 				pDock->fPostHideOffset = 1;  // pour que les icones demandant l'attention plus tard soient visibles.
1664 				return FALSE;
1665 			}
1666 		}
1667 	}
1668 	else if (pDock->fPostHideOffset > 0 && pDock->fPostHideOffset < 1)  // the post-hiding animation is running.
1669 	{
1670 		pDock->fPostHideOffset += 1./myBackendsParam.iHideNbSteps;
1671 		if (pDock->fPostHideOffset > .99)
1672 		{
1673 			pDock->fPostHideOffset = 1.;
1674 			return FALSE;
1675 		}
1676 	}
1677 	else  // else no hiding animation is running.
1678 		return FALSE;
1679 	return TRUE;
1680 }
1681 
_cairo_dock_show(CairoDock * pDock)1682 static gboolean _cairo_dock_show (CairoDock *pDock)
1683 {
1684 	pDock->fHideOffset -= 1./myBackendsParam.iUnhideNbSteps;
1685 	if (pDock->fHideOffset < 0.01)
1686 	{
1687 		pDock->fHideOffset = 0;
1688 		cairo_dock_allow_entrance (pDock);
1689 		gldi_dialogs_replace_all ();  // we need it here so that a modal dialog is replaced when the dock unhides (else it would stay behind).
1690 		return FALSE;
1691 	}
1692 	return TRUE;
1693 }
1694 
_cairo_dock_handle_inserting_removing_icons(CairoDock * pDock)1695 static gboolean _cairo_dock_handle_inserting_removing_icons (CairoDock *pDock)
1696 {
1697 	gboolean bRecalculateIcons = FALSE;
1698 	GList* ic = pDock->icons, *next_ic;
1699 	Icon *pIcon;
1700 	while (ic != NULL)
1701 	{
1702 		pIcon = ic->data;
1703 		if (pIcon->fInsertRemoveFactor == (gdouble)0.05)  // end of removal animation -> the icon will be detached (at least)
1704 		{
1705 			GList *prev_ic = ic->prev;
1706 			Icon *pPrevIcon = (prev_ic ? prev_ic->data : NULL);
1707 			if (GLDI_OBJECT_IS_AUTO_SEPARATOR_ICON (pPrevIcon))  // this icon will maybe disappear with pIcon, so take the previous one
1708 				prev_ic = prev_ic->prev;
1709 
1710 			gboolean bIsAppli = CAIRO_DOCK_IS_NORMAL_APPLI (pIcon);
1711 			if (bIsAppli)  // it's a valid appli icon that hides itself (for instance, because the window was unminimized with bHideVisibleApplis=true) => just detach it
1712 			{
1713 				cd_message ("cette appli (%s) est toujours valide, on la detache juste", pIcon->cName);
1714 				pIcon->fInsertRemoveFactor = 0.;  // on le fait avant le reload, sinon l'icone n'est pas rechargee.
1715 				if (!pIcon->pAppli->bIsHidden && myTaskbarParam.bHideVisibleApplis)  // on lui remet l'image normale qui servira d'embleme lorsque l'icone sera inseree a nouveau dans le dock.
1716 					cairo_dock_reload_icon_image (pIcon, CAIRO_CONTAINER (pDock));
1717 				pDock = gldi_appli_icon_detach (pIcon);
1718 				if (pDock == NULL)  // the dock has been destroyed (empty class sub-dock).
1719 				{
1720 					return FALSE;
1721 				}
1722 			}
1723 			else
1724 			{
1725 				cd_message (" - %s va etre supprimee", pIcon->cName);
1726 
1727 				gldi_icon_detach (pIcon);
1728 				if (pIcon->cClass != NULL && pDock == cairo_dock_get_class_subdock (pIcon->cClass))  // appli icon in its class sub-dock => destroy the class sub-dock if it becomes empty (we don't want an empty sub-dock).
1729 				{
1730 					gboolean bEmptyClassSubDock = cairo_dock_check_class_subdock_is_empty (pDock, pIcon->cClass);
1731 					if (bEmptyClassSubDock)
1732 					{
1733 						gldi_object_unref (GLDI_OBJECT (pIcon));
1734 						return FALSE;
1735 					}
1736 				}
1737 
1738 				gldi_object_delete (GLDI_OBJECT(pIcon));
1739 			}
1740 			next_ic = (prev_ic ? prev_ic->next : pDock->icons);
1741 		}
1742 		else
1743 		{
1744 			if (pIcon->fInsertRemoveFactor == (gdouble)-0.05)  // end of appearance animation
1745 			{
1746 				pIcon->fInsertRemoveFactor = 0;  // cela n'arrete pas l'animation, qui peut se poursuivre meme apres que l'icone ait atteint sa taille maximale.
1747 				bRecalculateIcons = TRUE;
1748 			}
1749 			else if (pIcon->fInsertRemoveFactor != 0)  // currently (dis)appearing
1750 			{
1751 				bRecalculateIcons = TRUE;
1752 			}
1753 			next_ic = ic->next;
1754 		}
1755 		ic = next_ic;
1756 	}
1757 
1758 	if (bRecalculateIcons)
1759 		cairo_dock_calculate_dock_icons (pDock);
1760 	return TRUE;
1761 }
1762 
_cairo_dock_dock_animation_loop(GldiContainer * pContainer)1763 static gboolean _cairo_dock_dock_animation_loop (GldiContainer *pContainer)
1764 {
1765 	CairoDock *pDock = CAIRO_DOCK (pContainer);
1766 	gboolean bContinue = FALSE;
1767 	gboolean bUpdateSlowAnimation = FALSE;
1768 	pContainer->iAnimationStep ++;
1769 	if (pContainer->iAnimationStep * pContainer->iAnimationDeltaT >= CAIRO_DOCK_MIN_SLOW_DELTA_T)
1770 	{
1771 		bUpdateSlowAnimation = TRUE;
1772 		pContainer->iAnimationStep = 0;
1773 		pContainer->bKeepSlowAnimation = FALSE;
1774 	}
1775 
1776 	if (pDock->bIsShrinkingDown)
1777 	{
1778 		pDock->bIsShrinkingDown = _cairo_dock_shrink_down (pDock);
1779 		cairo_dock_redraw_container (CAIRO_CONTAINER (pDock));
1780 		bContinue |= pDock->bIsShrinkingDown;
1781 	}
1782 	if (pDock->bIsGrowingUp)
1783 	{
1784 		pDock->bIsGrowingUp = _cairo_dock_grow_up (pDock);
1785 		cairo_dock_redraw_container (CAIRO_CONTAINER (pDock));
1786 		bContinue |= pDock->bIsGrowingUp;
1787 	}
1788 	if (pDock->bIsHiding)
1789 	{
1790 		//g_print ("le dock se cache\n");
1791 		pDock->bIsHiding = _cairo_dock_hide (pDock);
1792 		gtk_widget_queue_draw (pContainer->pWidget);  // on n'utilise pas cairo_dock_redraw_container, sinon a la derniere iteration, le dock etant cache, la fonction ne le redessine pas.
1793 		bContinue |= pDock->bIsHiding;
1794 	}
1795 	if (pDock->bIsShowing)
1796 	{
1797 		pDock->bIsShowing = _cairo_dock_show (pDock);
1798 		cairo_dock_redraw_container (CAIRO_CONTAINER (pDock));
1799 		bContinue |= pDock->bIsShowing;
1800 	}
1801 	//g_print (" => %d, %d\n", pDock->bIsShrinkingDown, pDock->bIsGrowingUp);
1802 
1803 	double fDockMagnitude = cairo_dock_calculate_magnitude (pDock->iMagnitudeIndex);
1804 	gboolean bIconIsAnimating;
1805 	gboolean bNoMoreDemandingAttention = FALSE;
1806 	Icon *icon;
1807 	GList *ic;
1808 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
1809 	{
1810 		icon = ic->data;
1811 
1812 		icon->fDeltaYReflection = 0;
1813 		if (myIconsParam.fAlphaAtRest != 1)
1814 			icon->fAlpha = fDockMagnitude + myIconsParam.fAlphaAtRest * (1 - fDockMagnitude);
1815 
1816 		bIconIsAnimating = FALSE;
1817 		if (bUpdateSlowAnimation)
1818 		{
1819 			gldi_object_notify (icon, NOTIFICATION_UPDATE_ICON_SLOW, icon, pDock, &bIconIsAnimating);
1820 			pContainer->bKeepSlowAnimation |= bIconIsAnimating;
1821 		}
1822 		gldi_object_notify (icon, NOTIFICATION_UPDATE_ICON, icon, pDock, &bIconIsAnimating);
1823 
1824 		if ((icon->bIsDemandingAttention || icon->bAlwaysVisible) && cairo_dock_is_hidden (pDock))  // animation d'une icone demandant l'attention dans un dock cache => on force le dessin qui normalement ne se fait pas.
1825 		{
1826 			gtk_widget_queue_draw (pContainer->pWidget);
1827 		}
1828 
1829 		bContinue |= bIconIsAnimating;
1830 		if (! bIconIsAnimating)
1831 		{
1832 			icon->iAnimationState = CAIRO_DOCK_STATE_REST;
1833 			if (icon->bIsDemandingAttention)
1834 			{
1835 				icon->bIsDemandingAttention = FALSE;  // the attention animation has finished by itself after the time it was planned for.
1836 				bNoMoreDemandingAttention = TRUE;
1837 			}
1838 		}
1839 	}
1840 	bContinue |= pContainer->bKeepSlowAnimation;
1841 
1842 	if (pDock->iVisibility == CAIRO_DOCK_VISI_KEEP_BELOW && bNoMoreDemandingAttention && ! pDock->bIsBelow && ! pContainer->bInside)
1843 	{
1844 		//g_print ("plus de raison d'etre devant\n");
1845 		cairo_dock_pop_down (pDock);
1846 	}
1847 
1848 	if (! _cairo_dock_handle_inserting_removing_icons (pDock))
1849 	{
1850 		cd_debug ("ce dock n'a plus de raison d'etre");
1851 		return FALSE;
1852 	}
1853 
1854 	if (bUpdateSlowAnimation)
1855 	{
1856 		gldi_object_notify (pDock, NOTIFICATION_UPDATE_SLOW, pDock, &pContainer->bKeepSlowAnimation);
1857 	}
1858 	gldi_object_notify (pDock, NOTIFICATION_UPDATE, pDock, &bContinue);
1859 
1860 	if (! bContinue && ! pContainer->bKeepSlowAnimation)
1861 	{
1862 		pContainer->iSidGLAnimation = 0;
1863 		return FALSE;
1864 	}
1865 	else
1866 		return TRUE;
1867 }
1868 
1869 static gboolean _on_dock_destroyed (GtkWidget *menu, GldiContainer *pContainer);
_on_menu_deactivated(G_GNUC_UNUSED GtkMenuShell * menu,CairoDock * pDock)1870 static void _on_menu_deactivated (G_GNUC_UNUSED GtkMenuShell *menu, CairoDock *pDock)
1871 {
1872 	//g_print ("\n+++ %s ()\n\n", __func__);
1873 	g_return_if_fail (CAIRO_DOCK_IS_DOCK (pDock));
1874 	if (pDock->bHasModalWindow)  // don't send the signal if the menu was already deactivated.
1875 	{
1876 		pDock->bHasModalWindow = FALSE;
1877 		cairo_dock_emit_leave_signal (CAIRO_CONTAINER (pDock));
1878 	}
1879 }
_on_menu_destroyed(GtkWidget * menu,CairoDock * pDock)1880 static void _on_menu_destroyed (GtkWidget *menu, CairoDock *pDock)
1881 {
1882 	//g_print ("\n+++ %s ()\n\n", __func__);
1883 	gldi_object_remove_notification (pDock,
1884 		NOTIFICATION_DESTROY,
1885 		(GldiNotificationFunc) _on_dock_destroyed,
1886 		menu);
1887 }
_on_dock_destroyed(GtkWidget * menu,GldiContainer * pContainer)1888 static gboolean _on_dock_destroyed (GtkWidget *menu, GldiContainer *pContainer)
1889 {
1890 	//g_print ("\n+++ %s ()\n\n", __func__);
1891 	g_signal_handlers_disconnect_matched
1892 		(menu,
1893 		G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
1894 		0,
1895 		0,
1896 		NULL,
1897 		_on_menu_deactivated,
1898 		pContainer);
1899 	g_signal_handlers_disconnect_matched
1900 		(menu,
1901 		G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
1902 		0,
1903 		0,
1904 		NULL,
1905 		_on_menu_destroyed,
1906 		pContainer);
1907 	return GLDI_NOTIFICATION_LET_PASS;
1908 }
_setup_menu(GldiContainer * pContainer,G_GNUC_UNUSED Icon * pIcon,GtkWidget * pMenu)1909 static void _setup_menu (GldiContainer *pContainer, G_GNUC_UNUSED Icon *pIcon, GtkWidget *pMenu)
1910 {
1911 	// keep the dock visible
1912 	CAIRO_DOCK (pContainer)->bHasModalWindow = TRUE;
1913 
1914 	// connect signals
1915 	if (g_signal_handler_find (pMenu,
1916 		G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
1917 		0,
1918 		0,
1919 		NULL,
1920 		_on_menu_deactivated,
1921 		pContainer) == 0)  // on evite de connecter 2 fois ce signal, donc la fonction est appelable plusieurs fois sur un meme menu.
1922 	{
1923 		// when the menu is deactivated, hide the dock back if necessary.
1924 		g_signal_connect (G_OBJECT (pMenu),
1925 			"deactivate",
1926 			G_CALLBACK (_on_menu_deactivated),
1927 			pContainer);
1928 		// when the menu is destroyed, remove the 'destroyed' notification on the dock.
1929 		g_signal_connect (G_OBJECT (pMenu),
1930 			"destroy",
1931 			G_CALLBACK (_on_menu_destroyed),
1932 			pContainer);
1933 		// when the dock is destroyed, remove the 2 signals on the menu.
1934 		gldi_object_register_notification (pContainer,
1935 			NOTIFICATION_DESTROY,
1936 			(GldiNotificationFunc) _on_dock_destroyed,
1937 			GLDI_RUN_AFTER, pMenu);  // the menu can stay alive even if the container disappear, so we need to ensure we won't call the callbacks then.
1938 	}
1939 }
1940 
_destroy_empty_dock(CairoDock * pDock)1941 static gboolean _destroy_empty_dock (CairoDock *pDock)
1942 {
1943 	if (pDock->bIconIsFlyingAway)  // keep the dock alive for now, in case the user re-inserts the flying icon in it.
1944 		return TRUE;
1945 	pDock->iSidDestroyEmptyDock = 0;
1946 	if (pDock->icons == NULL && pDock->iRefCount == 0 && ! pDock->bIsMainDock)  // le dock est toujours a detruire.
1947 	{
1948 		cd_debug ("The dock '%s' is empty. No icon, no dock.", pDock->cDockName);
1949 		gldi_object_unref (GLDI_OBJECT(pDock));
1950 	}
1951 	return FALSE;
1952 }
_detach_icon(GldiContainer * pContainer,Icon * icon)1953 static void _detach_icon (GldiContainer *pContainer, Icon *icon)
1954 {
1955 	CairoDock *pDock = CAIRO_DOCK (pContainer);
1956 	cd_debug ("%s (%s)", __func__, icon->cName);
1957 
1958 	//\___________________ On trouve l'icone et ses 2 voisins.
1959 	GList *prev_ic = NULL, *ic, *next_ic;
1960 	Icon *pPrevIcon = NULL, *pNextIcon = NULL;
1961 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
1962 	{
1963 		if (ic->data == icon)
1964 		{
1965 			prev_ic = ic->prev;
1966 			next_ic = ic->next;
1967 			if (prev_ic)
1968 				pPrevIcon = prev_ic->data;
1969 			if (next_ic)
1970 				pNextIcon = next_ic->data;
1971 			break;
1972 		}
1973 	}
1974 	g_return_if_fail (ic != NULL);  // not found (shouldn't happen)
1975 
1976 	//\___________________ On stoppe ses animations.
1977 	gldi_icon_stop_animation (icon);
1978 
1979 	//\___________________ On desactive sa miniature.
1980 	if (icon->pAppli != NULL)
1981 	{
1982 		//cd_debug ("on desactive la miniature de %s (Xid : %lx)", icon->cName, icon->Xid);
1983 		gldi_window_set_thumbnail_area (icon->pAppli, 0, 0, 0, 0);
1984 	}
1985 
1986 	//\___________________ On l'enleve de la liste.
1987 	pDock->icons = g_list_delete_link (pDock->icons, ic);
1988 	ic = NULL;
1989 	pDock->fFlatDockWidth -= icon->fWidth + myIconsParam.iIconGap;
1990 
1991 	//\___________________ On enleve le separateur si c'est la derniere icone de son type.
1992 	if (! CAIRO_DOCK_IS_AUTOMATIC_SEPARATOR (icon))
1993 	{
1994 		if ((pPrevIcon == NULL || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pPrevIcon)) && CAIRO_DOCK_IS_AUTOMATIC_SEPARATOR (pNextIcon))
1995 		{
1996 			pDock->icons = g_list_delete_link (pDock->icons, next_ic);  // optimisation
1997 			next_ic = NULL;
1998 			pDock->fFlatDockWidth -= pNextIcon->fWidth + myIconsParam.iIconGap;
1999 			cairo_dock_set_icon_container (pNextIcon, NULL);
2000 			gldi_object_unref (GLDI_OBJECT (pNextIcon));
2001 			pNextIcon = NULL;
2002 		}
2003 		if ((pNextIcon == NULL || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon)) && CAIRO_DOCK_IS_AUTOMATIC_SEPARATOR (pPrevIcon))
2004 		{
2005 			pDock->icons = g_list_delete_link (pDock->icons, prev_ic);  // optimisation
2006 			prev_ic = NULL;
2007 			pDock->fFlatDockWidth -= pPrevIcon->fWidth + myIconsParam.iIconGap;
2008 			cairo_dock_set_icon_container (pPrevIcon, NULL);
2009 			gldi_object_unref (GLDI_OBJECT (pPrevIcon));
2010 			pPrevIcon = NULL;
2011 		}
2012 	}
2013 
2014 	//\___________________ Cette icone realisait peut-etre le max des hauteurs, comme on l'enleve on recalcule ce max.
2015 	Icon *pOtherIcon;
2016 	if (icon->fHeight >= pDock->iMaxIconHeight)
2017 	{
2018 		pDock->iMaxIconHeight = 0;
2019 		for (ic = pDock->icons; ic != NULL; ic = ic->next)
2020 		{
2021 			pOtherIcon = ic->data;
2022 			if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pOtherIcon))
2023 			{
2024 				pDock->iMaxIconHeight = MAX (pDock->iMaxIconHeight, pOtherIcon->fHeight);
2025 				if (pOtherIcon->fHeight == icon->fHeight)  // on sait qu'on n'ira pas plus haut.
2026 					break;
2027 			}
2028 		}
2029 	}
2030 
2031 	//\___________________ On la remet a la taille normale en vue d'une reinsertion quelque part.
2032 	icon->fWidth /= pDock->container.fRatio;
2033 	icon->fHeight /= pDock->container.fRatio;
2034 
2035 	//\___________________ On prevoit le redessin de l'icone pointant sur le sous-dock.
2036 	if (pDock->iRefCount != 0 && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))
2037 	{
2038 		cairo_dock_trigger_redraw_subdock_content (pDock);
2039 	}
2040 
2041 	//\___________________ On prevoit la destruction du dock si c'est un dock principal qui devient vide.
2042 	if (pDock->iRefCount == 0 && pDock->icons == NULL && ! pDock->bIsMainDock)  // on supprime les docks principaux vides.
2043 	{
2044 		if (pDock->iSidDestroyEmptyDock == 0)
2045 			pDock->iSidDestroyEmptyDock = g_idle_add ((GSourceFunc) _destroy_empty_dock, pDock);
2046 	}
2047 	else
2048 	{
2049 		cairo_dock_trigger_update_dock_size (pDock);
2050 	}
2051 
2052 	//\___________________ Notify everybody.
2053 	icon->fInsertRemoveFactor = 0.;
2054 	gldi_object_notify (pDock, NOTIFICATION_REMOVE_ICON, icon, pDock);
2055 
2056 	//\___________________ unset the container, now that it's completely detached from it.
2057 	g_free (icon->cParentDockName);
2058 	icon->cParentDockName = NULL;
2059 }
2060 
_insert_icon(GldiContainer * pContainer,Icon * icon,gboolean bAnimateIcon)2061 static void _insert_icon (GldiContainer *pContainer, Icon *icon, gboolean bAnimateIcon)
2062 {
2063 	CairoDock *pDock = CAIRO_DOCK (pContainer);
2064 
2065 	cd_debug ("insert %s in %s", icon->cName, gldi_dock_get_name (pDock));
2066 
2067 	if (icon->cParentDockName == NULL)
2068 		icon->cParentDockName = g_strdup (gldi_dock_get_name (pDock));
2069 
2070 	//\______________ check if a separator is needed (ie, if the group of the new icon (not its order) is new).
2071 	gboolean bSeparatorNeeded = FALSE;
2072 	if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))
2073 	{
2074 		Icon *pSameTypeIcon = cairo_dock_get_first_icon_of_group (pDock->icons, icon->iGroup);
2075 		if (pSameTypeIcon == NULL && pDock->icons != NULL)
2076 		{
2077 			bSeparatorNeeded = TRUE;
2078 		}
2079 	}
2080 
2081 	//\______________ insert the icon in the list.
2082 	if (icon->fOrder == CAIRO_DOCK_LAST_ORDER)
2083 	{
2084 		Icon *pLastIcon = cairo_dock_get_last_icon_of_order (pDock->icons, icon->iGroup);
2085 		if (pLastIcon != NULL)
2086 			icon->fOrder = pLastIcon->fOrder + 1;
2087 		else
2088 			icon->fOrder = 1;
2089 	}
2090 
2091 	pDock->icons = g_list_insert_sorted (pDock->icons,
2092 		icon,
2093 		(GCompareFunc)cairo_dock_compare_icons_order);
2094 
2095 	//\______________ set the icon size, now that it's inside a container.
2096 	int wi = icon->image.iWidth, hi = icon->image.iHeight;
2097 	cairo_dock_set_icon_size_in_dock (pDock, icon);
2098 
2099 	if (wi != cairo_dock_icon_get_allocated_width (icon) || hi != cairo_dock_icon_get_allocated_height (icon)  // if size has changed, reload the buffers
2100 	|| (! icon->image.pSurface && ! icon->image.iTexture))  // might happen, for instance if the icon is a launcher pinned on a desktop and was detached before being loaded.
2101 		cairo_dock_trigger_load_icon_buffers (icon);
2102 
2103 	pDock->fFlatDockWidth += myIconsParam.iIconGap + icon->fWidth;
2104 	if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))
2105 		pDock->iMaxIconHeight = MAX (pDock->iMaxIconHeight, icon->fHeight);
2106 
2107 	//\______________ insert a separator if needed.
2108 	if (bSeparatorNeeded)
2109 	{
2110 		// insert a separator after if needed
2111 		Icon *pNextIcon = cairo_dock_get_next_icon (pDock->icons, icon);
2112 		if (pNextIcon != NULL && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
2113 		{
2114 			Icon *pSeparatorIcon = gldi_auto_separator_icon_new (icon, pNextIcon);
2115 			gldi_icon_insert_in_container (pSeparatorIcon, CAIRO_CONTAINER(pDock), ! CAIRO_DOCK_ANIMATE_ICON);
2116 		}
2117 
2118 		// insert a separator before if needed
2119 		Icon *pPrevIcon = cairo_dock_get_previous_icon (pDock->icons, icon);
2120 		if (pPrevIcon != NULL && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pPrevIcon))
2121 		{
2122 			Icon *pSeparatorIcon = gldi_auto_separator_icon_new (pPrevIcon, icon);
2123 			gldi_icon_insert_in_container (pSeparatorIcon, CAIRO_CONTAINER(pDock), ! CAIRO_DOCK_ANIMATE_ICON);
2124 		}
2125 	}
2126 
2127 	//\______________ On effectue les actions demandees.
2128 	if (bAnimateIcon)
2129 	{
2130 		if (cairo_dock_animation_will_be_visible (pDock))
2131 			icon->fInsertRemoveFactor = - 0.95;
2132 		else
2133 			icon->fInsertRemoveFactor = - 0.05;
2134 		cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
2135 	}
2136 	else
2137 		icon->fInsertRemoveFactor = 0.;
2138 
2139 	cairo_dock_trigger_update_dock_size (pDock);
2140 
2141 	if (pDock->iRefCount != 0 && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))  // on prevoit le redessin de l'icone pointant sur le sous-dock.
2142 	{
2143 		cairo_dock_trigger_redraw_subdock_content (pDock);
2144 	}
2145 
2146 	if (icon->pSubDock != NULL)
2147 		gldi_subdock_synchronize_orientation (icon->pSubDock, pDock, FALSE);
2148 
2149 	//\______________ Notify everybody.
2150 	gldi_object_notify (pDock, NOTIFICATION_INSERT_ICON, icon, pDock);  /// TODO: make it a Container notification...
2151 }
2152 
gldi_dock_init_internals(CairoDock * pDock)2153 void gldi_dock_init_internals (CairoDock *pDock)
2154 {
2155 	pDock->container.iface.animation_loop = _cairo_dock_dock_animation_loop;
2156 	pDock->container.iface.setup_menu = _setup_menu;
2157 	pDock->container.iface.detach_icon = _detach_icon;
2158 	pDock->container.iface.insert_icon = _insert_icon;
2159 
2160 	//\__________________ set up its window
2161 	GtkWidget *pWindow = pDock->container.pWidget;
2162 	gtk_container_set_border_width (GTK_CONTAINER (pWindow), 0);
2163 	gtk_window_set_gravity (GTK_WINDOW (pWindow), GDK_GRAVITY_STATIC);
2164 	gtk_window_set_type_hint (GTK_WINDOW (pWindow), GDK_WINDOW_TYPE_HINT_DOCK);  // window must not be mapped
2165 
2166 	//\__________________ connect to events.
2167 	gtk_widget_add_events (pWindow,
2168 		GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK |
2169 		GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
2170 		GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
2171 
2172 	g_signal_connect (G_OBJECT (pWindow),
2173 		"draw",
2174 		G_CALLBACK (_on_expose),
2175 		pDock);
2176 	g_signal_connect (G_OBJECT (pWindow),
2177 		"configure-event",
2178 		G_CALLBACK (_on_configure),
2179 		pDock);
2180 	g_signal_connect (G_OBJECT (pWindow),
2181 		"key-release-event",
2182 		G_CALLBACK (_on_key_release),
2183 		pDock);
2184 	g_signal_connect (G_OBJECT (pWindow),
2185 		"key-press-event",
2186 		G_CALLBACK (_on_key_release),
2187 		pDock);
2188 	g_signal_connect (G_OBJECT (pWindow),
2189 		"button-press-event",
2190 		G_CALLBACK (_on_button_press),
2191 		pDock);
2192 	g_signal_connect (G_OBJECT (pWindow),
2193 		"button-release-event",
2194 		G_CALLBACK (_on_button_press),
2195 		pDock);
2196 	g_signal_connect (G_OBJECT (pWindow),
2197 		"scroll-event",
2198 		G_CALLBACK (_on_scroll),
2199 		pDock);
2200 	g_signal_connect (G_OBJECT (pWindow),
2201 		"motion-notify-event",
2202 		G_CALLBACK (_on_motion_notify),
2203 		pDock);
2204 	g_signal_connect (G_OBJECT (pWindow),
2205 		"enter-notify-event",
2206 		G_CALLBACK (_on_enter_notify),
2207 		pDock);
2208 	g_signal_connect (G_OBJECT (pWindow),
2209 		"leave-notify-event",
2210 		G_CALLBACK (_on_leave_notify),
2211 		pDock);
2212 	gldi_container_enable_drop (CAIRO_CONTAINER (pDock),
2213 		G_CALLBACK (_on_drag_data_received),
2214 		pDock);
2215 	g_signal_connect (G_OBJECT (pWindow),
2216 		"drag-motion",
2217 		G_CALLBACK (_on_drag_motion),
2218 		pDock);
2219 	g_signal_connect (G_OBJECT (pWindow),
2220 		"drag-leave",
2221 		G_CALLBACK (_on_drag_leave),
2222 		pDock);
2223 	/*g_signal_connect (G_OBJECT (pWindow),
2224 		"drag-drop",
2225 		G_CALLBACK (_on_drag_drop),
2226 		pDock);*/
2227 
2228 	gtk_widget_show_all (pDock->container.pWidget);
2229 }
2230 
2231 
2232   ///////////////
2233  /// FACTORY ///
2234 ///////////////
2235 
gldi_dock_new(const gchar * cDockName)2236 CairoDock *gldi_dock_new (const gchar *cDockName)
2237 {
2238 	CairoDockAttr attr;
2239 	memset (&attr, 0, sizeof (CairoDockAttr));
2240 	attr.cDockName = cDockName;
2241 	return (CairoDock*)gldi_object_new (&myDockObjectMgr, &attr);
2242 }
2243 
gldi_subdock_new(const gchar * cDockName,const gchar * cRendererName,CairoDock * pParentDock,GList * pIconList)2244 CairoDock *gldi_subdock_new (const gchar *cDockName, const gchar *cRendererName, CairoDock *pParentDock, GList *pIconList)
2245 {
2246 	CairoDockAttr attr;
2247 	memset (&attr, 0, sizeof (CairoDockAttr));
2248 	attr.bSubDock = TRUE;
2249 	attr.cDockName = cDockName;
2250 	attr.cRendererName = cRendererName;
2251 	attr.pParentDock = pParentDock;
2252 	attr.pIconList = pIconList;
2253 	return (CairoDock*)gldi_object_new (&myDockObjectMgr, &attr);
2254 }
2255 
2256 
cairo_dock_remove_icons_from_dock(CairoDock * pDock,CairoDock * pReceivingDock)2257 void cairo_dock_remove_icons_from_dock (CairoDock *pDock, CairoDock *pReceivingDock)
2258 {
2259 	g_return_if_fail (pReceivingDock != NULL);
2260 	GList *pIconsList = pDock->icons;
2261 	pDock->icons = NULL;
2262 	Icon *icon;
2263 	GList *ic;
2264 	for (ic = pIconsList; ic != NULL; ic = ic->next)
2265 	{
2266 		icon = ic->data;
2267 
2268 		cairo_dock_set_icon_container (icon, NULL);  // manually detach the icon
2269 
2270 		gldi_theme_icon_write_container_name_in_conf_file (icon, pReceivingDock->cDockName);
2271 
2272 		cd_debug (" on re-attribue %s au dock %s", icon->cName, pReceivingDock->cDockName);
2273 		gldi_icon_insert_in_container (icon, CAIRO_CONTAINER(pReceivingDock), CAIRO_DOCK_ANIMATE_ICON);
2274 
2275 		if (CAIRO_DOCK_IS_APPLET (icon))
2276 		{
2277 			icon->pModuleInstance->pContainer = CAIRO_CONTAINER (pReceivingDock);  // astuce pour ne pas avoir a recharger le fichier de conf ^_^
2278 			icon->pModuleInstance->pDock = pReceivingDock;
2279 			gldi_object_reload (GLDI_OBJECT(icon->pModuleInstance), FALSE);
2280 		}
2281 		else if (cairo_dock_get_icon_data_renderer (icon) != NULL)
2282 			cairo_dock_reload_data_renderer_on_icon (icon, CAIRO_CONTAINER (pReceivingDock));
2283 	}
2284 
2285 	g_list_free (pIconsList);
2286 }
2287 
2288 
cairo_dock_reload_buffers_in_dock(CairoDock * pDock,gboolean bRecursive,gboolean bUpdateIconSize)2289 void cairo_dock_reload_buffers_in_dock (CairoDock *pDock, gboolean bRecursive, gboolean bUpdateIconSize)
2290 {
2291 	//g_print ("************%s (%d, %d)\n", __func__, pDock->bIsMainDock, bRecursive);
2292 	if (bUpdateIconSize && pDock->bGlobalIconSize)
2293 		pDock->iIconSize = myIconsParam.iIconWidth;
2294 
2295 	// for each icon, reload its buffer (size may change).
2296 	Icon* icon;
2297 	GList* ic;
2298 	for (ic = pDock->icons; ic != NULL; ic = ic->next)
2299 	{
2300 		icon = ic->data;
2301 
2302 		if (CAIRO_DOCK_IS_APPLET (icon))  // for an applet, we need to let the module know that the size or the theme has changed, so that it can reload its private buffers.
2303 		{
2304 			gldi_object_reload (GLDI_OBJECT(icon->pModuleInstance), FALSE);
2305 		}
2306 		else
2307 		{
2308 			if (bUpdateIconSize)
2309 			{
2310 				cairo_dock_icon_set_requested_size (icon, 0, 0);
2311 				cairo_dock_set_icon_size_in_dock (pDock, icon);
2312 			}
2313 
2314 			if (bUpdateIconSize && cairo_dock_get_icon_data_renderer (icon) != NULL)  // we need to reload the DataRenderer to use the new size
2315 			{
2316 				cairo_dock_load_icon_buffers (icon, CAIRO_CONTAINER (pDock));  // the DataRenderer uses the ImageBuffer's size on loading, so we need to load it now
2317 				cairo_dock_reload_data_renderer_on_icon (icon, CAIRO_CONTAINER (pDock));
2318 			}
2319 			else
2320 			{
2321 				cairo_dock_trigger_load_icon_buffers (icon);
2322 			}
2323 		}
2324 
2325 		if (bRecursive && icon->pSubDock != NULL)  // we handle the sub-dock for applets too, so that they don't need to care.
2326 		{
2327 			if (bUpdateIconSize)
2328 				icon->pSubDock->iIconSize = pDock->iIconSize;
2329 			cairo_dock_reload_buffers_in_dock (icon->pSubDock, bRecursive, bUpdateIconSize);
2330 		}
2331 	}
2332 
2333 	if (bUpdateIconSize)
2334 	{
2335 		cairo_dock_update_dock_size (pDock);
2336 	}
2337 	gtk_widget_queue_draw (pDock->container.pWidget);
2338 }
2339 
2340 
cairo_dock_set_icon_size_in_dock(CairoDock * pDock,Icon * icon)2341 void cairo_dock_set_icon_size_in_dock (CairoDock *pDock, Icon *icon)
2342 {
2343 	if (pDock->pRenderer && pDock->pRenderer->set_icon_size)  // the view wants to decide the icons size.
2344 	{
2345 		pDock->pRenderer->set_icon_size (icon, pDock);
2346 	}
2347 	else  // generic method: icon extent = base size * max zoom
2348 	{
2349 		int wi, hi;  // icon size (icon size displayed at rest, as defined in the config)
2350 		int wa, ha;  // allocated size (surface/texture).
2351 		gboolean bIsHorizontal = (pDock->container.bIsHorizontal || (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon) && myIconsParam.bRevolveSeparator));
2352 
2353 		// get the displayed icon size as defined in the config
2354 		if (! pDock->bGlobalIconSize && pDock->iIconSize != 0)
2355 		{
2356 			wi = hi = pDock->iIconSize;
2357 		}
2358 		else  // same size as main dock.
2359 		{
2360 			wi = myIconsParam.iIconWidth;
2361 			hi = myIconsParam.iIconHeight;
2362 		}
2363 
2364 		if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))  // separators have their own size.
2365 		{
2366 			wi = myIconsParam.iSeparatorWidth;
2367 			hi = MIN (myIconsParam.iSeparatorHeight, hi);
2368 		}
2369 
2370 		// take into account the requested displayed size if any
2371 		int wir = cairo_dock_icon_get_requested_display_width (icon);
2372 		if (wir != 0)
2373 			wi = wir;
2374 		int hir = cairo_dock_icon_get_requested_display_height (icon);
2375 		if (hir != 0)
2376 			hi = MIN (hir, hi);  // limit the icon height to the default height.
2377 
2378 		// get the requested size if any
2379 		wa = cairo_dock_icon_get_requested_width (icon);
2380 		ha = cairo_dock_icon_get_requested_height (icon);
2381 
2382 		// compute the missing size (allocated or displayed).
2383 		double fMaxScale = 1 + myIconsParam.fAmplitude;
2384 		if (wa == 0)
2385 		{
2386 			wa = (bIsHorizontal ? wi : hi) * fMaxScale;
2387 		}
2388 		else
2389 		{
2390 			if (bIsHorizontal)
2391 				wi = wa / fMaxScale;
2392 			else
2393 				hi = wa / fMaxScale;
2394 		}
2395 		if (ha == 0)
2396 		{
2397 			ha = (bIsHorizontal ? hi : wi) * fMaxScale;
2398 		}
2399 		else
2400 		{
2401 			if (bIsHorizontal)
2402 				hi = ha / fMaxScale;
2403 			else
2404 				wi = ha / fMaxScale;
2405 		}
2406 
2407 		// set both allocated and displayed size
2408 		cairo_dock_icon_set_allocated_size (icon, wa, ha);
2409 		icon->fWidth = wi;
2410 		icon->fHeight = hi;
2411 	}
2412 	// take into account the current ratio
2413 	icon->fWidth *= pDock->container.fRatio;
2414 	icon->fHeight *= pDock->container.fRatio;
2415 }
2416 
2417 
cairo_dock_create_redirect_texture_for_dock(CairoDock * pDock)2418 void cairo_dock_create_redirect_texture_for_dock (CairoDock *pDock)
2419 {
2420 	if (! g_openglConfig.bFboAvailable)
2421 		return ;
2422 	if (pDock->iRedirectedTexture == 0)
2423 	{
2424 		pDock->iRedirectedTexture = cairo_dock_create_texture_from_raw_data (NULL,
2425 			(pDock->container.bIsHorizontal ? pDock->container.iWidth : pDock->container.iHeight),
2426 			(pDock->container.bIsHorizontal ? pDock->container.iHeight : pDock->container.iWidth));
2427 	}
2428 	if (pDock->iFboId == 0)
2429 		glGenFramebuffersEXT(1, &pDock->iFboId);
2430 }
2431