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 <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 
24 #include <GL/gl.h>
25 #include <GL/glu.h>
26 
27 #include "gldi-config.h"
28 #include "cairo-dock-icon-factory.h"
29 #include "cairo-dock-icon-facility.h"
30 #include "cairo-dock-container.h"
31 #include "cairo-dock-image-buffer.h"
32 #include "cairo-dock-draw.h"
33 #include "cairo-dock-draw-opengl.h"
34 #include "cairo-dock-log.h"
35 #include "cairo-dock-desklet-factory.h"
36 #include "cairo-dock-dock-manager.h"
37 #include "cairo-dock-dock-facility.h"
38 #include "cairo-dock-backends-manager.h"
39 #include "cairo-dock-surface-factory.h"
40 #include "cairo-dock-animations.h"  // cairo_dock_launch_animation
41 #include "cairo-dock-launcher-manager.h"  // cairo_dock_search_icon_s_path
42 #include "cairo-dock-windows-manager.h"  // gldi_windows_get_active
43 #include "cairo-dock-desktop-manager.h"
44 #include "cairo-dock-style-manager.h"
45 #include "cairo-dock-dialog-manager.h"
46 #include "cairo-dock-dialog-factory.h"
47 
48 extern gboolean g_bUseOpenGL;
49 extern CairoDock *g_pMainDock;
50 
51 
_compute_dialog_sizes(CairoDialog * pDialog)52 static void _compute_dialog_sizes (CairoDialog *pDialog)
53 {
54 	pDialog->iMessageWidth = pDialog->iIconSize + pDialog->iTextWidth + (pDialog->iTextWidth != 0 ? 2 : 0) * CAIRO_DIALOG_TEXT_MARGIN - pDialog->iIconOffsetX;  // icone + marge + texte + marge.
55 	pDialog->iMessageHeight = MAX (pDialog->iIconSize - pDialog->iIconOffsetY, pDialog->iTextHeight) + (pDialog->pInteractiveWidget != NULL ? CAIRO_DIALOG_VGAP : 0);  // (icone/texte + marge) + widget + (marge + boutons) + pointe.
56 
57 	if (pDialog->pButtons != NULL)
58 	{
59 		pDialog->iButtonsWidth = pDialog->iNbButtons * myDialogsParam.iDialogButtonWidth + (pDialog->iNbButtons - 1) * CAIRO_DIALOG_BUTTON_GAP + 2 * CAIRO_DIALOG_TEXT_MARGIN;  // marge + bouton1 + ecart + bouton2 + marge.
60 		pDialog->iButtonsHeight = CAIRO_DIALOG_VGAP + myDialogsParam.iDialogButtonHeight;  // il y'a toujours quelque chose au-dessus (texte et/ou widget)
61 	}
62 
63 	pDialog->iBubbleWidth = MAX (pDialog->iInteractiveWidth, MAX (pDialog->iButtonsWidth, MAX (pDialog->iMessageWidth, pDialog->iMinFrameWidth)));
64 	pDialog->iBubbleHeight = pDialog->iMessageHeight + pDialog->iInteractiveHeight + pDialog->iButtonsHeight;
65 	if (pDialog->iBubbleWidth == 0)  // precaution.
66 		pDialog->iBubbleWidth = 20;
67 	if (pDialog->iBubbleHeight == 0)
68 		pDialog->iBubbleHeight = 10;
69 
70 	pDialog->iComputedWidth = pDialog->iLeftMargin + pDialog->iBubbleWidth + pDialog->iRightMargin;
71 	pDialog->iComputedHeight = pDialog->iTopMargin + pDialog->iBubbleHeight + pDialog->iBottomMargin + pDialog->iMinBottomGap;  // all included.
72 
73 	pDialog->container.iWidth = pDialog->iComputedWidth;
74 	pDialog->container.iHeight = pDialog->iComputedHeight;
75 }
76 
on_expose_dialog(G_GNUC_UNUSED GtkWidget * pWidget,cairo_t * pCairoContext,CairoDialog * pDialog)77 static gboolean on_expose_dialog (G_GNUC_UNUSED GtkWidget *pWidget, cairo_t *pCairoContext, CairoDialog *pDialog)
78 {
79 	//g_print ("%s (%dx%d ; %d;%d)\n", __func__, pDialog->container.iWidth, pDialog->container.iHeight, pExpose->area.x, pExpose->area.y);
80 	/* int x, y;
81 	// OpenGL renderers are not ready for dialogs.
82 	if (g_bUseOpenGL && (pDialog->pDecorator == NULL || pDialog->pDecorator->render_opengl != NULL) && (pDialog->pRenderer == NULL || pDialog->pRenderer->render_opengl != NULL))
83 	{
84 		if (! gldi_glx_begin_draw_container (CAIRO_CONTAINER (pDialog)))
85 			return FALSE;
86 
87 		if (pDialog->pDecorator != NULL && pDialog->pDecorator->render_opengl != NULL)
88 		{
89 			glPushMatrix ();
90 			pDialog->pDecorator->render_opengl (pDialog);
91 			glPopMatrix ();
92 		}
93 
94 		gldi_object_notify (pDialog, NOTIFICATION_RENDER, pDialog, NULL);
95 
96 		gldi_glx_end_draw_container (CAIRO_CONTAINER (pDialog));
97 	}
98 	else
99 	{*/
100 		cairo_dock_init_drawing_context_on_container (CAIRO_CONTAINER (pDialog), pCairoContext);
101 
102 		if (pDialog->pDecorator != NULL)
103 		{
104 			cairo_save (pCairoContext);
105 			pDialog->pDecorator->render (pCairoContext, pDialog);
106 			cairo_restore (pCairoContext);
107 		}
108 
109 		gldi_object_notify (pDialog, NOTIFICATION_RENDER, pDialog, pCairoContext);
110 	//}
111 	return FALSE;
112 }
113 
on_expose_dialog_after(G_GNUC_UNUSED GtkWidget * pWidget,cairo_t * pCairoContext,CairoDialog * pDialog)114 static gboolean on_expose_dialog_after (G_GNUC_UNUSED GtkWidget *pWidget, cairo_t *pCairoContext, CairoDialog *pDialog)
115 {
116 	if (pDialog->fAppearanceCounter < 1.)  // modify the opacity after the interaction widget has been drawn by GTK.
117 	{
118 		double fAlpha = pDialog->fAppearanceCounter * pDialog->fAppearanceCounter;
119 		cairo_rectangle (pCairoContext,
120 			0,
121 			0,
122 			pDialog->container.iWidth,
123 			pDialog->container.iHeight);
124 		cairo_set_line_width (pCairoContext, 0);
125 		cairo_set_operator (pCairoContext, CAIRO_OPERATOR_DEST_OUT);
126 		cairo_set_source_rgba (pCairoContext, 0.0, 0.0, 0.0, 1. - fAlpha);
127 		cairo_fill (pCairoContext);
128 	}
129 	return FALSE;
130 }
131 
_cairo_dock_set_dialog_input_shape(CairoDialog * pDialog)132 static void _cairo_dock_set_dialog_input_shape (CairoDialog *pDialog)
133 {
134 	if (pDialog->pShapeBitmap != NULL)
135 		cairo_region_destroy (pDialog->pShapeBitmap);
136 
137 	pDialog->pShapeBitmap = gldi_container_create_input_shape (CAIRO_CONTAINER (pDialog),
138 		0,
139 		0,
140 		1,
141 		1);  // workaround a bug in X with fully transparent window => let 1 pixel ON.
142 
143 	gldi_container_set_input_shape (CAIRO_CONTAINER (pDialog), pDialog->pShapeBitmap);
144 }
145 
on_configure_dialog(G_GNUC_UNUSED GtkWidget * pWidget,GdkEventConfigure * pEvent,CairoDialog * pDialog)146 static gboolean on_configure_dialog (G_GNUC_UNUSED GtkWidget* pWidget,
147 	GdkEventConfigure* pEvent,
148 	CairoDialog *pDialog)
149 {
150 	//g_print ("%s (%dx%d, %d;%d) [%d]\n", __func__, pEvent->width, pEvent->height, pEvent->x, pEvent->y, pDialog->bPositionForced);
151 	if (pEvent->width <= CAIRO_DIALOG_MIN_SIZE && pEvent->height <= CAIRO_DIALOG_MIN_SIZE && ! pDialog->bNoInput)
152 	{
153 		pDialog->container.bInside = FALSE;
154 		return FALSE;
155 	}
156 
157 	//\____________ get dialog size and position.
158 	int iPrevWidth = pDialog->container.iWidth, iPrevHeight = pDialog->container.iHeight;
159 	pDialog->container.iWidth = pEvent->width;
160 	pDialog->container.iHeight = pEvent->height;
161 	pDialog->container.iWindowPositionX = pEvent->x;
162 	pDialog->container.iWindowPositionY = pEvent->y;
163 
164 	//\____________ if an interactive widget is present, internal sizes may have changed.
165 	if (pDialog->pInteractiveWidget != NULL)
166 	{
167 		int w = pDialog->iInteractiveWidth, h = pDialog->iInteractiveHeight;
168 		GtkRequisition requisition;
169 		gtk_widget_get_preferred_size (pDialog->pInteractiveWidget, &requisition, NULL);
170 		pDialog->iInteractiveWidth = requisition.width;
171 		pDialog->iInteractiveHeight = requisition.height;
172 		//g_print ("  pInteractiveWidget : %dx%d\n", pDialog->iInteractiveWidth, pDialog->iInteractiveHeight);
173 		_compute_dialog_sizes (pDialog);
174 
175 		if (w != pDialog->iInteractiveWidth || h != pDialog->iInteractiveHeight)
176 		{
177 			gldi_dialogs_replace_all ();
178 			/*Icon *pIcon = pDialog->pIcon;
179 			if (pIcon != NULL)
180 			{
181 				GldiContainer *pContainer = cairo_dock_search_container_from_icon (pIcon);
182 				cairo_dock_place_dialog (pDialog, pContainer);
183 			}*/
184 		}
185 	}
186 	//g_print ("dialog size: %dx%d / %dx%d\n", pEvent->width, pEvent->height, pDialog->iComputedWidth, pDialog->iComputedHeight);
187 
188 	//\____________ set input shape if size has changed or if no shape yet.
189 	if (pDialog->bNoInput && (iPrevWidth != pEvent->width || iPrevHeight != pEvent->height || ! pDialog->pShapeBitmap))
190 	{
191 		_cairo_dock_set_dialog_input_shape (pDialog);
192 		pDialog->container.bInside = FALSE;
193 	}
194 
195 	//\____________ force position for buggy WM (Compiz).
196 	if (pDialog->iComputedWidth == pEvent->width && pDialog->iComputedHeight == pEvent->height && (pEvent->y != pDialog->iComputedPositionY || pEvent->x != pDialog->iComputedPositionX) && pDialog->bPositionForced == 3)
197 	{
198 		pDialog->container.bInside = FALSE;
199 		cd_debug ("force to %d;%d", pDialog->iComputedPositionX, pDialog->iComputedPositionY);
200 		/*gtk_window_move (GTK_WINDOW (pDialog->container.pWidget),
201 			pDialog->iComputedPositionX,
202 			pDialog->iComputedPositionY);
203 		*/pDialog->bPositionForced ++;
204 	}
205 
206 	gtk_widget_queue_draw (pDialog->container.pWidget);  // les widgets internes peuvent avoir changer de taille sans que le dialogue n'en ait change, il faut donc redessiner tout le temps.
207 
208 	return FALSE;
209 }
210 
on_unmap_dialog(GtkWidget * pWidget,G_GNUC_UNUSED GdkEvent * pEvent,CairoDialog * pDialog)211 static gboolean on_unmap_dialog (GtkWidget* pWidget,
212 	G_GNUC_UNUSED GdkEvent *pEvent,
213 	CairoDialog *pDialog)
214 {
215 	//g_print ("unmap dialog (bAllowMinimize:%d, visible:%d)\n", pDialog->bAllowMinimize, GTK_WIDGET_VISIBLE (pWidget));
216 	if (! pDialog->bAllowMinimize)  // it's an unexpected unmap event
217 	{
218 		if (pDialog->pUnmapTimer)  // see if it happened just after an event that we expected
219 		{
220 			double fElapsedTime = g_timer_elapsed (pDialog->pUnmapTimer, NULL);
221 			//g_print ("fElapsedTime : %fms\n", fElapsedTime);
222 			if (fElapsedTime < .2)  // it's a 2nd unmap event just after the first one, ignore it, it's just some noise from the WM
223 				return TRUE;
224 		}
225 		gtk_window_present (GTK_WINDOW (pWidget));  // counter it, we don't want dialogs to be hidden
226 	}
227 	else  // expected event, it's an unmap that we triggered with 'gldi_dialog_hide', so let pass it
228 	{
229 		pDialog->bAllowMinimize = FALSE;
230 		if (pDialog->pUnmapTimer != NULL)
231 			g_timer_destroy (pDialog->pUnmapTimer);
232 		pDialog->pUnmapTimer = g_timer_new ();  // remember the time it arrived
233 	}
234 	return TRUE;  // stops other handlers from being invoked for the event.
235 }
236 
on_map_dialog(G_GNUC_UNUSED GtkWidget * pWidget,G_GNUC_UNUSED GdkEvent * pEvent,CairoDialog * pDialog)237 static gboolean on_map_dialog (G_GNUC_UNUSED GtkWidget* pWidget,
238 	G_GNUC_UNUSED GdkEvent *pEvent,
239 	CairoDialog *pDialog)
240 {
241 	if (pDialog->pInteractiveWidget)
242 	{
243 		gldi_container_present (CAIRO_CONTAINER (pDialog));
244 	}
245 	return FALSE;
246 }
247 
on_button_press_widget(G_GNUC_UNUSED GtkWidget * widget,GdkEventButton * pButton,CairoDialog * pDialog)248 static gboolean on_button_press_widget (G_GNUC_UNUSED GtkWidget *widget,
249 	GdkEventButton *pButton,
250 	CairoDialog *pDialog)
251 {
252 	cd_debug ("press button on widget");
253 	// memorize the time when the user clicked on the widget.
254 	pDialog->iButtonPressTime = pButton->time;
255 	return FALSE;
256 }
257 
_cairo_dock_add_dialog_internal_box(CairoDialog * pDialog,int iWidth,int iHeight,gboolean bCanResize)258 static GtkWidget *_cairo_dock_add_dialog_internal_box (CairoDialog *pDialog, int iWidth, int iHeight, gboolean bCanResize)
259 {
260 	GtkWidget *pBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
261 	if (iWidth != 0 && iHeight != 0)
262 		g_object_set (pBox, "height-request", iHeight, "width-request", iWidth, NULL);
263 	else if (iWidth != 0)
264 			g_object_set (pBox, "width-request", iWidth, NULL);
265 	else if (iHeight != 0)
266 			g_object_set (pBox, "height-request", iHeight, NULL);
267 	gtk_box_pack_start (GTK_BOX (pDialog->pWidgetLayout),
268 		pBox,
269 		bCanResize,
270 		bCanResize,
271 		0);
272 	return pBox;
273 }
274 
_cairo_dock_create_dialog_text_surface(const gchar * cText,gboolean bUseMarkup,int * iTextWidth,int * iTextHeight)275 static cairo_surface_t *_cairo_dock_create_dialog_text_surface (const gchar *cText, gboolean bUseMarkup, int *iTextWidth, int *iTextHeight)
276 {
277 	if (cText == NULL)
278 		return NULL;
279 
280 	myDialogsParam.dialogTextDescription.bUseMarkup = bUseMarkup;  // slight optimization, rather than duplicating the TextDescription each time.
281 	cairo_surface_t *pSurface = cairo_dock_create_surface_from_text (cText,
282 		&myDialogsParam.dialogTextDescription,
283 		iTextWidth,
284 		iTextHeight);
285 	myDialogsParam.dialogTextDescription.bUseMarkup = FALSE;  // by default
286 	return pSurface;
287 }
288 
_cairo_dock_create_dialog_icon_surface(const gchar * cImageFilePath,Icon * pIcon,int iDesiredSize,int * iIconSize)289 static cairo_surface_t *_cairo_dock_create_dialog_icon_surface (const gchar *cImageFilePath, Icon *pIcon, int iDesiredSize, int *iIconSize)
290 {
291 	if (cImageFilePath == NULL)
292 		return NULL;
293 	if (iDesiredSize == 0)
294 		iDesiredSize = myDialogsParam.iDialogIconSize;
295 	cairo_surface_t *pIconBuffer = NULL;
296 	if (strcmp (cImageFilePath, "same icon") == 0)
297 	{
298 		if (pIcon && pIcon->image.pSurface)
299 		{
300 			int iWidth, iHeight;
301 			cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
302 			pIconBuffer = cairo_dock_duplicate_surface (pIcon->image.pSurface,
303 				iWidth, iHeight,
304 				iDesiredSize, iDesiredSize);
305 		}
306 		else if (pIcon && pIcon->cFileName)
307 		{
308 			pIconBuffer = cairo_dock_create_surface_from_image_simple (pIcon->cFileName,
309 				iDesiredSize,
310 				iDesiredSize);
311 		}
312 	}
313 	else
314 	{
315 		pIconBuffer = cairo_dock_create_surface_from_image_simple (cImageFilePath,
316 			iDesiredSize,
317 			iDesiredSize);
318 	}
319 	if (pIconBuffer != NULL)
320 		*iIconSize = iDesiredSize;
321 	return pIconBuffer;
322 }
323 
_animation_loop(GldiContainer * pContainer)324 static gboolean _animation_loop (GldiContainer *pContainer)
325 {
326 	CairoDialog *pDialog = CAIRO_DIALOG (pContainer);
327 	gboolean bContinue = FALSE;
328 	gboolean bUpdateSlowAnimation = FALSE;
329 	pContainer->iAnimationStep ++;
330 	if (pContainer->iAnimationStep * pContainer->iAnimationDeltaT >= CAIRO_DOCK_MIN_SLOW_DELTA_T)
331 	{
332 		bUpdateSlowAnimation = TRUE;
333 		pContainer->iAnimationStep = 0;
334 		pContainer->bKeepSlowAnimation = FALSE;
335 	}
336 
337 	if (pDialog->fAppearanceCounter < 1)
338 	{
339 		pDialog->fAppearanceCounter += .08;
340 		if (pDialog->fAppearanceCounter > .99)
341 		{
342 			pDialog->fAppearanceCounter = 1.;
343 		}
344 		else
345 		{
346 			bContinue = TRUE;
347 		}
348 	}
349 
350 	if (bUpdateSlowAnimation)
351 	{
352 		gldi_object_notify (pDialog, NOTIFICATION_UPDATE_SLOW, pDialog, &pContainer->bKeepSlowAnimation);
353 	}
354 
355 	gldi_object_notify (pDialog, NOTIFICATION_UPDATE, pDialog, &bContinue);
356 
357 	cairo_dock_redraw_container (CAIRO_CONTAINER (pDialog));
358 	if (! bContinue && ! pContainer->bKeepSlowAnimation)
359 	{
360 		pContainer->iSidGLAnimation = 0;
361 		return FALSE;
362 	}
363 	else
364 		return TRUE;
365 }
366 
gldi_dialog_init_internals(CairoDialog * pDialog,CairoDialogAttr * pAttribute)367 void gldi_dialog_init_internals (CairoDialog *pDialog, CairoDialogAttr *pAttribute)
368 {
369 	pDialog->container.iface.animation_loop = _animation_loop;
370 
371 	//\________________ set up the window
372 	GtkWidget *pWindow = pDialog->container.pWidget;
373 	gtk_window_set_title (GTK_WINDOW (pWindow), "cairo-dock-dialog");
374 	if (! pAttribute->pInteractiveWidget && ! pAttribute->pActionFunc)  // not an interactive dialog
375 		gtk_window_set_type_hint (GTK_WINDOW (pDialog->container.pWidget), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);  // pour ne pas prendre le focus.
376 
377 	gtk_widget_add_events (pWindow, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
378 	gtk_window_resize (GTK_WINDOW (pWindow), CAIRO_DIALOG_MIN_SIZE, CAIRO_DIALOG_MIN_SIZE);
379 	gtk_window_set_keep_above (GTK_WINDOW (pWindow), TRUE);
380 
381 	pDialog->pIcon = pAttribute->pIcon;
382 	if (pAttribute->bForceAbove)  // try to force it above other windows (with most WM, it will still stay below fullscreen windows).
383 	{
384 		gtk_window_set_keep_above (GTK_WINDOW (pDialog->container.pWidget), TRUE);
385 		gtk_window_set_type_hint (GTK_WINDOW (pDialog->container.pWidget), GDK_WINDOW_TYPE_HINT_DOCK);  // should be called before the window becomes visible
386 	}
387 
388 	//\________________ load the message
389 	if (pAttribute->cText != NULL)
390 	{
391 		pDialog->cText = g_strdup (pAttribute->cText);  // it may be a const string, so duplicate it
392 		pDialog->pTextBuffer = _cairo_dock_create_dialog_text_surface (pAttribute->cText,
393 			pAttribute->bUseMarkup,
394 			&pDialog->iTextWidth, &pDialog->iTextHeight);
395 		///pDialog->iTextTexture = cairo_dock_create_texture_from_surface (pDialog->pTextBuffer);
396 	}
397 	pDialog->bUseMarkup = pAttribute->bUseMarkup;  // remember this attribute, in case another text is set (with cairo_dock_set_dialog_message).
398 
399 	//\________________ load the icon
400 	if (pAttribute->cImageFilePath != NULL)
401 	{
402 		pDialog->pIconBuffer = _cairo_dock_create_dialog_icon_surface (pAttribute->cImageFilePath, pAttribute->pIcon, pAttribute->iIconSize, &pDialog->iIconSize);
403 		///pDialog->iIconTexture = cairo_dock_create_texture_from_surface (pDialog->pIconBuffer);
404 	}
405 
406 	//\________________ load the interactive widget
407 	if (pAttribute->pInteractiveWidget != NULL)
408 	{
409 		pDialog->pInteractiveWidget = pAttribute->pInteractiveWidget;
410 
411 		GtkRequisition requisition;
412 		gtk_widget_get_preferred_size (pAttribute->pInteractiveWidget, &requisition, NULL);
413 		pDialog->iInteractiveWidth = requisition.width;
414 		pDialog->iInteractiveHeight = requisition.height;
415 	}
416 
417 	//\________________ load the buttons
418 	pDialog->pUserData = pAttribute->pUserData;
419 	pDialog->pFreeUserDataFunc = pAttribute->pFreeDataFunc;
420 	if (pAttribute->cButtonsImage != NULL && pAttribute->pActionFunc != NULL)
421 	{
422 		int i;
423 		for (i = 0; pAttribute->cButtonsImage[i] != NULL; i++);
424 
425 		pDialog->iNbButtons = i;
426 		pDialog->action_on_answer = pAttribute->pActionFunc;
427 		pDialog->pButtons = g_new0 (CairoDialogButton, pDialog->iNbButtons);
428 		const gchar *cButtonImage;
429 		for (i = 0; i < pDialog->iNbButtons; i++)
430 		{
431 			cButtonImage = pAttribute->cButtonsImage[i];
432 			if (strcmp (cButtonImage, "ok") == 0)
433 			{
434 				pDialog->pButtons[i].iDefaultType = 1;
435 			}
436 			else if (strcmp (cButtonImage, "cancel") == 0)
437 			{
438 				pDialog->pButtons[i].iDefaultType = 0;
439 			}
440 			else
441 			{
442 				gchar *cButtonPath;
443 				if (*cButtonImage != '/')
444 					cButtonPath = cairo_dock_search_icon_s_path (cButtonImage,
445 						MAX (myDialogsParam.iDialogButtonWidth, myDialogsParam.iDialogButtonHeight));
446 				else
447 					cButtonPath = (gchar*)cButtonImage;
448 				pDialog->pButtons[i].pSurface = cairo_dock_create_surface_from_image_simple (cButtonPath,
449 					myDialogsParam.iDialogButtonWidth,
450 					myDialogsParam.iDialogButtonHeight);
451 				if (cButtonPath != cButtonImage)
452 					g_free (cButtonPath);
453 				///pDialog->pButtons[i].iTexture = cairo_dock_create_texture_from_surface (pDialog->pButtons[i].pSurface);
454 			}
455 		}
456 	}
457 	else
458 	{
459 		pDialog->bNoInput = pAttribute->bNoInput;
460 	}
461 
462 	//\________________ set a decorator.
463 	cairo_dock_set_dialog_decorator_by_name (pDialog, (pAttribute->cDecoratorName ? pAttribute->cDecoratorName : myDialogsParam.cDecoratorName));
464 	if (pDialog->pDecorator != NULL)
465 		pDialog->pDecorator->set_size (pDialog);
466 
467 	//\________________ Maintenant qu'on connait tout, on calcule les tailles des divers elements.
468 	_compute_dialog_sizes (pDialog);
469 	pDialog->container.iWidth = pDialog->iBubbleWidth + pDialog->iLeftMargin + pDialog->iRightMargin;
470 	pDialog->container.iHeight = pDialog->iBubbleHeight + pDialog->iTopMargin + pDialog->iBottomMargin + pDialog->iMinBottomGap;
471 
472 	//\________________ On reserve l'espace pour les decorations.
473 	GtkWidget *pMainHBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
474 	gtk_container_add (GTK_CONTAINER (pDialog->container.pWidget), pMainHBox);
475 	pDialog->pLeftPaddingBox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
476 	g_object_set (pDialog->pLeftPaddingBox, "width-request", pDialog->iLeftMargin, NULL);
477 	gtk_box_pack_start (GTK_BOX (pMainHBox),
478 		pDialog->pLeftPaddingBox,
479 		FALSE,
480 		FALSE,
481 		0);
482 
483 	pDialog->pWidgetLayout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
484 	gtk_box_pack_start (GTK_BOX (pMainHBox),
485 		pDialog->pWidgetLayout,
486 		FALSE,
487 		FALSE,
488 		0);
489 
490 	pDialog->pRightPaddingBox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
491 	g_object_set (pDialog->pRightPaddingBox, "width-request", pDialog->iRightMargin, NULL);
492 	gtk_box_pack_start (GTK_BOX (pMainHBox),
493 		pDialog->pRightPaddingBox,
494 		FALSE,
495 		FALSE,
496 		0);
497 
498 	//\________________ On reserve l'espace pour les elements.
499 	if (pDialog->container.bDirectionUp)
500 		pDialog->pTopWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iTopMargin, FALSE);
501 	else
502 		pDialog->pTipWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iMinBottomGap + pDialog->iBottomMargin, TRUE);
503 	if (pDialog->iMessageWidth != 0 && pDialog->iMessageHeight != 0)
504 	{
505 		pDialog->pMessageWidget = _cairo_dock_add_dialog_internal_box (pDialog, pDialog->iMessageWidth, pDialog->iMessageHeight, FALSE);
506 	}
507 	if (pDialog->pInteractiveWidget != NULL)
508 	{
509 		gtk_box_pack_start (GTK_BOX (pDialog->pWidgetLayout),
510 			pDialog->pInteractiveWidget,
511 			FALSE,
512 			FALSE,
513 			0);
514 		gtk_window_present (GTK_WINDOW (pDialog->container.pWidget));
515 		gtk_widget_grab_focus (pDialog->pInteractiveWidget);
516 
517 		// set a MenuItem style to the dialog, so that the interactive widget can use the style defined for menu-items (either from the GTK theme, or from our own .css), and therefore be well integrated into the dialog, as if it was inside a menu.
518 		GtkStyleContext *ctx = gtk_widget_get_style_context (pDialog->pWidgetLayout);
519 		gtk_style_context_add_class (ctx, myDialogsParam.bUseDefaultColors && myStyleParam.bUseSystemColors ? GTK_STYLE_CLASS_MENUITEM : "gldimenuitem");
520 	}
521 	if (pDialog->pButtons != NULL)
522 	{
523 		pDialog->pButtonsWidget = _cairo_dock_add_dialog_internal_box (pDialog, pDialog->iButtonsWidth, pDialog->iButtonsHeight, FALSE);
524 	}
525 	if (pDialog->container.bDirectionUp)
526 		pDialog->pTipWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iMinBottomGap + pDialog->iBottomMargin, TRUE);
527 	else
528 		pDialog->pTopWidget = _cairo_dock_add_dialog_internal_box (pDialog, 0, pDialog->iTopMargin, TRUE);
529 
530 	gtk_widget_show_all (pDialog->container.pWidget);
531 
532 	//\________________ load the input shape.
533 	if (pDialog->bNoInput)
534 	{
535 		_cairo_dock_set_dialog_input_shape (pDialog);
536 	}
537 
538 	//\________________ connect the signals to the window
539 	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
540 		"draw",
541 		G_CALLBACK (on_expose_dialog),
542 		pDialog);
543 	g_signal_connect_after (G_OBJECT (pDialog->container.pWidget),
544 		"draw",
545 		G_CALLBACK (on_expose_dialog_after),
546 		pDialog);
547 	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
548 		"configure-event",
549 		G_CALLBACK (on_configure_dialog),
550 		pDialog);
551 	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
552 		"unmap-event",
553 		G_CALLBACK (on_unmap_dialog),
554 		pDialog);  // prevent dialogs from being hidden (for instance by a 'show-desktop' event), because they might be modal
555 	g_signal_connect (G_OBJECT (pDialog->container.pWidget),
556 		"map-event",
557 		G_CALLBACK (on_map_dialog),
558 		pDialog);  // some WM (like GS) prevent the focus to be taken, so we have to force it whenever the dialog is shown (creation or unhide).
559 	if (pDialog->pInteractiveWidget != NULL && pDialog->pButtons == NULL)  // the dialog has no button to be closed, so it can be closed by clicking on it. But some widget (like the GTK calendar) let pass the click to their parent (= the dialog), which then close it. To prevent this, we memorize the last click on the widget.
560 		g_signal_connect (G_OBJECT (pDialog->pInteractiveWidget),
561 			"button-press-event",
562 			G_CALLBACK (on_button_press_widget),
563 			pDialog);
564 
565 	cairo_dock_launch_animation (CAIRO_CONTAINER (pDialog));
566 }
567 
gldi_dialog_new(CairoDialogAttr * pAttribute)568 CairoDialog *gldi_dialog_new (CairoDialogAttr *pAttribute)
569 {
570 	if (!pAttribute->bForceAbove)
571 	{
572 		GldiWindowActor *pActiveAppli = gldi_windows_get_active ();
573 		if (pActiveAppli && pActiveAppli->bIsFullScreen && gldi_window_is_on_current_desktop (pActiveAppli))
574 		{
575 			cd_debug ("skip dialog since current fullscreen window would mask it");
576 			return NULL;
577 		}
578 	}
579 	pAttribute->cattr.bNoOpengl = TRUE;
580 	cd_debug ("%s (%s, %s, %x, %x, (%p;%p))", __func__, pAttribute->cText, pAttribute->cImageFilePath, pAttribute->pInteractiveWidget, pAttribute->pActionFunc, pAttribute->pIcon, pAttribute->pContainer);
581 	return (CairoDialog*)gldi_object_new (&myDialogObjectMgr, pAttribute);
582 }
583 
584 
gldi_dialog_show(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,double fTimeLength,const gchar * cIconPath,GtkWidget * pInteractiveWidget,CairoDockActionOnAnswerFunc pActionFunc,gpointer data,GFreeFunc pFreeDataFunc)585 CairoDialog *gldi_dialog_show (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, double fTimeLength, const gchar *cIconPath, GtkWidget *pInteractiveWidget, CairoDockActionOnAnswerFunc pActionFunc, gpointer data, GFreeFunc pFreeDataFunc)
586 {
587 	if (pIcon != NULL && cairo_dock_icon_is_being_removed (pIcon))  // icone en cours de suppression.
588 	{
589 		cd_debug ("dialog skipped for %s (%.2f)", pIcon->cName, pIcon->fInsertRemoveFactor);
590 		return NULL;
591 	}
592 
593 	CairoDialogAttr attr;
594 	memset (&attr, 0, sizeof (CairoDialogAttr));
595 	attr.cText = (gchar *)cText;
596 	attr.cImageFilePath = (gchar *)cIconPath;
597 	attr.pInteractiveWidget = pInteractiveWidget;
598 	attr.pActionFunc = pActionFunc;
599 	attr.pUserData = data;
600 	attr.pFreeDataFunc = pFreeDataFunc;
601 	attr.iTimeLength = (int) fTimeLength;
602 	const gchar *cDefaultActionButtons[3] = {"ok", "cancel", NULL};
603 	if (pActionFunc != NULL)
604 		attr.cButtonsImage = cDefaultActionButtons;
605 	attr.pIcon = pIcon;
606 	attr.pContainer = pContainer;
607 
608 	return gldi_dialog_new (&attr);
609 }
610 
gldi_dialog_show_temporary_with_icon_printf(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,double fTimeLength,const gchar * cIconPath,...)611 CairoDialog *gldi_dialog_show_temporary_with_icon_printf (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, double fTimeLength, const gchar *cIconPath, ...)
612 {
613 	g_return_val_if_fail (cText != NULL, NULL);
614 	va_list args;
615 	va_start (args, cIconPath);
616 	gchar *cFullText = g_strdup_vprintf (cText, args);
617 	CairoDialog *pDialog = gldi_dialog_show (cFullText, pIcon, pContainer, fTimeLength, cIconPath, NULL, NULL, NULL, NULL);
618 	g_free (cFullText);
619 	va_end (args);
620 	return pDialog;
621 }
622 
gldi_dialog_show_temporary_with_icon(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,double fTimeLength,const gchar * cIconPath)623 CairoDialog *gldi_dialog_show_temporary_with_icon (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, double fTimeLength, const gchar *cIconPath)
624 {
625 	g_return_val_if_fail (cText != NULL, NULL);
626 	return gldi_dialog_show (cText, pIcon, pContainer, fTimeLength, cIconPath, NULL, NULL, NULL, NULL);
627 }
628 
gldi_dialog_show_temporary(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,double fTimeLength)629 CairoDialog *gldi_dialog_show_temporary (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, double fTimeLength)
630 {
631 	g_return_val_if_fail (cText != NULL, NULL);
632 	return gldi_dialog_show (cText, pIcon, pContainer, fTimeLength, NULL, NULL, NULL, NULL, NULL);
633 }
634 
gldi_dialog_show_temporary_with_default_icon(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,double fTimeLength)635 CairoDialog *gldi_dialog_show_temporary_with_default_icon (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, double fTimeLength)
636 {
637 	g_return_val_if_fail (cText != NULL, NULL);
638 
639 	const gchar *cIconPath = GLDI_SHARE_DATA_DIR"/"CAIRO_DOCK_ICON;
640 
641 	CairoDialogAttr attr;
642 	memset (&attr, 0, sizeof (CairoDialogAttr));
643 	attr.cText = cText;
644 	attr.cImageFilePath = cIconPath;
645 	attr.iTimeLength = (int) fTimeLength;
646 	attr.pIcon = pIcon;
647 	attr.pContainer = pContainer;
648 
649 	return gldi_dialog_new (&attr);
650 }
651 
_cairo_dock_make_entry_for_dialog(const gchar * cTextForEntry)652 static inline GtkWidget *_cairo_dock_make_entry_for_dialog (const gchar *cTextForEntry)
653 {
654 	GtkWidget *pWidget = gtk_entry_new ();
655 	gtk_entry_set_has_frame (GTK_ENTRY (pWidget), FALSE);
656 	g_object_set (pWidget, "width-request", CAIRO_DIALOG_MIN_ENTRY_WIDTH, NULL);
657 	if (cTextForEntry != NULL)
658 		gtk_entry_set_text (GTK_ENTRY (pWidget), cTextForEntry);
659 	return pWidget;
660 }
_cairo_dock_make_hscale_for_dialog(double fValueForHScale,double fMaxValueForHScale)661 static inline GtkWidget *_cairo_dock_make_hscale_for_dialog (double fValueForHScale, double fMaxValueForHScale)
662 {
663 	GtkWidget *pWidget = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, fMaxValueForHScale, fMaxValueForHScale / 100.);
664 	gtk_scale_set_digits (GTK_SCALE (pWidget), 2);
665 	gtk_range_set_value (GTK_RANGE (pWidget), fValueForHScale);
666 
667 	g_object_set (pWidget, "width-request", CAIRO_DIALOG_MIN_SCALE_WIDTH, NULL);
668 	return pWidget;
669 }
670 
gldi_dialog_show_with_question(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,const gchar * cIconPath,CairoDockActionOnAnswerFunc pActionFunc,gpointer data,GFreeFunc pFreeDataFunc)671 CairoDialog *gldi_dialog_show_with_question (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, const gchar *cIconPath, CairoDockActionOnAnswerFunc pActionFunc, gpointer data, GFreeFunc pFreeDataFunc)
672 {
673 	return gldi_dialog_show (cText, pIcon, pContainer, 0, cIconPath, NULL, pActionFunc, data, pFreeDataFunc);
674 }
675 
gldi_dialog_show_with_entry(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,const gchar * cIconPath,const gchar * cTextForEntry,CairoDockActionOnAnswerFunc pActionFunc,gpointer data,GFreeFunc pFreeDataFunc)676 CairoDialog *gldi_dialog_show_with_entry (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, const gchar *cIconPath, const gchar *cTextForEntry, CairoDockActionOnAnswerFunc pActionFunc, gpointer data, GFreeFunc pFreeDataFunc)
677 {
678 	//GtkWidget *pWidget = cairo_dock_build_common_interactive_widget_for_dialog (cTextForEntry, -1, -1);
679 	GtkWidget *pWidget = _cairo_dock_make_entry_for_dialog (cTextForEntry);
680 
681 	return gldi_dialog_show (cText, pIcon, pContainer, 0, cIconPath, pWidget, pActionFunc, data, pFreeDataFunc);
682 }
683 
gldi_dialog_show_with_value(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,const gchar * cIconPath,double fValue,double fMaxValue,CairoDockActionOnAnswerFunc pActionFunc,gpointer data,GFreeFunc pFreeDataFunc)684 CairoDialog *gldi_dialog_show_with_value (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, const gchar *cIconPath, double fValue, double fMaxValue, CairoDockActionOnAnswerFunc pActionFunc, gpointer data, GFreeFunc pFreeDataFunc)
685 {
686 	fValue = MAX (0., fValue);
687 	fValue = MIN (fMaxValue, fValue);
688 	//GtkWidget *pWidget = cairo_dock_build_common_interactive_widget_for_dialog (NULL, fValue, 1.);
689 	GtkWidget *pWidget = _cairo_dock_make_hscale_for_dialog (fValue, fMaxValue);
690 
691 	return gldi_dialog_show (cText, pIcon, pContainer, 0, cIconPath, pWidget, pActionFunc, data, pFreeDataFunc);
692 }
693 
gldi_dialog_show_general_message(const gchar * cMessage,double fTimeLength)694 CairoDialog *gldi_dialog_show_general_message (const gchar *cMessage, double fTimeLength)
695 {
696 	Icon *pIcon = gldi_icons_get_any_without_dialog ();
697 	return gldi_dialog_show_temporary (cMessage, pIcon, CAIRO_CONTAINER (g_pMainDock), fTimeLength);
698 }
699 
700 
_cairo_dock_get_answer_from_dialog(int iClickedButton,G_GNUC_UNUSED GtkWidget * pInteractiveWidget,gpointer * data,CairoDialog * pDialog)701 static void _cairo_dock_get_answer_from_dialog (int iClickedButton, G_GNUC_UNUSED GtkWidget *pInteractiveWidget, gpointer *data, CairoDialog *pDialog)
702 {
703 	cd_message ("%s (%d)", __func__, iClickedButton);
704 	int *iAnswerBuffer = data[0];
705 	// GMainLoop *pBlockingLoop = data[1];
706 
707 	gldi_dialog_steal_interactive_widget (pDialog);  // le dialogue disparaitra apres cette fonction, mais le widget interactif doit rester.
708 
709 	*iAnswerBuffer = iClickedButton;
710 }
_on_free_blocking_dialog(gpointer * data)711 static void _on_free_blocking_dialog (gpointer *data)
712 {
713 	GMainLoop *pBlockingLoop = data[1];
714 	if (g_main_loop_is_running (pBlockingLoop))
715 		g_main_loop_quit (pBlockingLoop);
716 }
gldi_dialog_show_and_wait(const gchar * cText,Icon * pIcon,GldiContainer * pContainer,const gchar * cIconPath,GtkWidget * pInteractiveWidget)717 int gldi_dialog_show_and_wait (const gchar *cText, Icon *pIcon, GldiContainer *pContainer, const gchar *cIconPath, GtkWidget *pInteractiveWidget)
718 {
719 	int iClickedButton = -3;
720 	GMainLoop *pBlockingLoop = g_main_loop_new (NULL, FALSE);
721 	gpointer data[2] = {&iClickedButton, pBlockingLoop};  // it's useless to allocate 'data' because this function will wait for an answer
722 
723 	CairoDialog *pDialog = gldi_dialog_show (cText,
724 		pIcon,
725 		pContainer,
726 		0.,
727 		cIconPath,
728 		pInteractiveWidget,
729 		(CairoDockActionOnAnswerFunc)_cairo_dock_get_answer_from_dialog,
730 		(gpointer) data,
731 		(GFreeFunc)_on_free_blocking_dialog);
732 
733 	if (pDialog != NULL)
734 	{
735 		pDialog->fAppearanceCounter = 1.;
736 		cd_debug ("Start the blocking loop...");
737 		g_main_loop_run (pBlockingLoop);
738 		cd_debug ("End of the blocking loop -> %d", iClickedButton);
739 	}
740 
741 	g_main_loop_unref (pBlockingLoop);
742 	return iClickedButton;
743 }
744 
745 
cairo_dock_steal_widget_from_its_container(GtkWidget * pWidget)746 GtkWidget *cairo_dock_steal_widget_from_its_container (GtkWidget *pWidget)
747 {
748 	g_return_val_if_fail (pWidget != NULL, NULL);
749 	GtkWidget *pContainer = gtk_widget_get_parent (pWidget);
750 	if (pContainer != NULL)
751 	{
752 		g_object_ref (G_OBJECT (pWidget));
753 		gtk_container_remove (GTK_CONTAINER (pContainer), pWidget);
754 	}
755 	return pWidget;
756 }
757 
gldi_dialog_steal_interactive_widget(CairoDialog * pDialog)758 GtkWidget *gldi_dialog_steal_interactive_widget (CairoDialog *pDialog)
759 {
760 	if (pDialog == NULL)
761 		return NULL;
762 
763 	GtkWidget *pInteractiveWidget = pDialog->pInteractiveWidget;
764 	if (pInteractiveWidget != NULL)
765 	{
766 		pInteractiveWidget = cairo_dock_steal_widget_from_its_container (pInteractiveWidget);
767 		pDialog->pInteractiveWidget = NULL;
768 
769 		// if we were monitoring the click events on the widget, stop it.
770 		g_signal_handlers_disconnect_matched (pInteractiveWidget,
771 			G_SIGNAL_MATCH_FUNC,
772 			0,
773 			0,
774 			NULL,
775 			on_button_press_widget,
776 			NULL);
777 	}
778 	return pInteractiveWidget;
779 }
780 
_redraw_icon_surface(CairoDialog * pDialog)781 static void _redraw_icon_surface (CairoDialog *pDialog)
782 {
783 	if (!pDialog->container.bUseReflect)
784 		gtk_widget_queue_draw_area (pDialog->container.pWidget,
785 			pDialog->iLeftMargin,
786 			(pDialog->container.bDirectionUp ?
787 				pDialog->iTopMargin :
788 				pDialog->container.iHeight - (pDialog->iTopMargin + pDialog->iBubbleHeight)),
789 			pDialog->iIconSize,
790 			pDialog->iIconSize);
791 	else
792 		gtk_widget_queue_draw (pDialog->container.pWidget);
793 }
794 
_redraw_text_surface(CairoDialog * pDialog)795 static void _redraw_text_surface (CairoDialog *pDialog)
796 {
797 	if (!pDialog->container.bUseReflect)
798 		gtk_widget_queue_draw_area (pDialog->container.pWidget,
799 			pDialog->iLeftMargin + pDialog->iIconSize + CAIRO_DIALOG_TEXT_MARGIN,
800 			(pDialog->container.bDirectionUp ?
801 				pDialog->iTopMargin :
802 				pDialog->container.iHeight - (pDialog->iTopMargin + pDialog->iBubbleHeight)),
803 			pDialog->iTextWidth,
804 			pDialog->iTextHeight);
805 	else
806 		gtk_widget_queue_draw (pDialog->container.pWidget);
807 }
808 
gldi_dialog_redraw_interactive_widget(CairoDialog * pDialog)809 void gldi_dialog_redraw_interactive_widget (CairoDialog *pDialog)
810 {
811 	if (!pDialog->container.bUseReflect)
812 		gtk_widget_queue_draw_area (pDialog->container.pWidget,
813 			pDialog->iLeftMargin,
814 			(pDialog->container.bDirectionUp ?
815 				pDialog->iTopMargin + pDialog->iMessageHeight :
816 				pDialog->container.iHeight - (pDialog->iTopMargin + pDialog->iBubbleHeight) + pDialog->iMessageHeight),
817 			pDialog->iInteractiveWidth,
818 			pDialog->iInteractiveHeight);
819 	else
820 		gtk_widget_queue_draw (pDialog->container.pWidget);
821 }
822 
823 
_set_icon_surface(CairoDialog * pDialog,cairo_surface_t * pNewIconSurface,int iNewIconSize)824 static void _set_icon_surface (CairoDialog *pDialog, cairo_surface_t *pNewIconSurface, int iNewIconSize)
825 {
826 	int iPrevMessageWidth = pDialog->iMessageWidth;
827 	int iPrevMessageHeight = pDialog->iMessageHeight;
828 
829 	cairo_surface_destroy (pDialog->pIconBuffer);
830 	if (pDialog->iIconTexture != 0)
831 		_cairo_dock_delete_texture (pDialog->iIconTexture);
832 
833 	pDialog->pIconBuffer = pNewIconSurface;
834 	if (! pNewIconSurface)
835 		iNewIconSize = 0;
836 
837 	if (pDialog->iIconSize != iNewIconSize)  // can happen if the dialog didn't have an icon before, or if the new one is NULL
838 	{
839 		pDialog->iIconSize = iNewIconSize;
840 		_compute_dialog_sizes (pDialog);
841 	}
842 
843 	// redraw
844 	if (pDialog->iMessageWidth != iPrevMessageWidth || pDialog->iMessageHeight != iPrevMessageHeight)
845 	{
846 		g_object_set (pDialog->pMessageWidget, "width-request", pDialog->iMessageWidth, "height-request", pDialog->iMessageHeight, NULL);  // inutile de replacer le dialogue puisque sa gravite fera le boulot.
847 
848 		gtk_widget_queue_draw (pDialog->container.pWidget);
849 	}
850 	else
851 	{
852 		_redraw_icon_surface (pDialog);
853 	}
854 }
855 
gldi_dialog_set_icon_surface(CairoDialog * pDialog,cairo_surface_t * pNewIconSurface,int iNewIconSize)856 void gldi_dialog_set_icon_surface (CairoDialog *pDialog, cairo_surface_t *pNewIconSurface, int iNewIconSize)
857 {
858 	int iIconSize = (pDialog->iIconSize != 0 ? pDialog->iIconSize : myDialogsParam.iDialogIconSize);
859 	cairo_surface_t *pIconBuffer = cairo_dock_duplicate_surface (pNewIconSurface, iNewIconSize, iNewIconSize, iIconSize, iIconSize);
860 	_set_icon_surface (pDialog, pIconBuffer, iIconSize);
861 }
862 
gldi_dialog_set_icon(CairoDialog * pDialog,const gchar * cImageFilePath)863 void gldi_dialog_set_icon (CairoDialog *pDialog, const gchar *cImageFilePath)
864 {
865 	int iIconSize = (pDialog->iIconSize != 0 ? pDialog->iIconSize : myDialogsParam.iDialogIconSize);
866 	cairo_surface_t *pIconBuffer = cairo_dock_create_surface_for_square_icon (cImageFilePath, iIconSize);
867 
868 	_set_icon_surface (pDialog, pIconBuffer, iIconSize);
869 }
870 
871 
_set_text_surface(CairoDialog * pDialog,cairo_surface_t * pNewTextSurface,int iNewTextWidth,int iNewTextHeight)872 static void _set_text_surface (CairoDialog *pDialog, cairo_surface_t *pNewTextSurface, int iNewTextWidth, int iNewTextHeight)
873 {
874 	int iPrevMessageWidth = pDialog->iMessageWidth;
875 	int iPrevMessageHeight = pDialog->iMessageHeight;
876 
877 	cairo_surface_destroy (pDialog->pTextBuffer);
878 	pDialog->pTextBuffer = pNewTextSurface;
879 	if (pDialog->iTextTexture != 0)
880 		_cairo_dock_delete_texture (pDialog->iTextTexture);
881 	///pDialog->iTextTexture = cairo_dock_create_texture_from_surface (pNewTextSurface);
882 
883 	pDialog->iTextWidth = iNewTextWidth;
884 	pDialog->iTextHeight = iNewTextHeight;
885 	_compute_dialog_sizes (pDialog);
886 
887 	if (pDialog->iMessageWidth != iPrevMessageWidth || pDialog->iMessageHeight != iPrevMessageHeight)
888 	{
889 		g_object_set (pDialog->pMessageWidget, "width-request", pDialog->iMessageWidth, "height-request", pDialog->iMessageHeight, NULL);  // inutile de replacer le dialogue puisque sa gravite fera le boulot.
890 
891 		gtk_widget_queue_draw (pDialog->container.pWidget);
892 
893 		gboolean bInside = pDialog->container.bInside;
894 		pDialog->container.bInside = FALSE;  // unfortunately the gravity is really badly handled by many WMs, so we have to replace he dialog ourselves :-/
895 		gldi_dialogs_replace_all ();
896 		pDialog->container.bInside = bInside;
897 	}
898 	else
899 	{
900 		_redraw_text_surface (pDialog);
901 	}
902 }
903 
gldi_dialog_set_message(CairoDialog * pDialog,const gchar * cMessage)904 void gldi_dialog_set_message (CairoDialog *pDialog, const gchar *cMessage)
905 {
906 	cd_debug ("%s", cMessage);
907 	int iNewTextWidth=0, iNewTextHeight=0;
908 	cairo_surface_t *pNewTextSurface = _cairo_dock_create_dialog_text_surface (cMessage, pDialog->bUseMarkup, &iNewTextWidth, &iNewTextHeight);
909 
910 	_set_text_surface (pDialog, pNewTextSurface, iNewTextWidth, iNewTextHeight);
911 
912 	g_free (pDialog->cText);
913 	pDialog->cText = g_strdup (cMessage);
914 }
gldi_dialog_set_message_printf(CairoDialog * pDialog,const gchar * cMessageFormat,...)915 void gldi_dialog_set_message_printf (CairoDialog *pDialog, const gchar *cMessageFormat, ...)
916 {
917 	g_return_if_fail (cMessageFormat != NULL);
918 	va_list args;
919 	va_start (args, cMessageFormat);
920 	gchar *cMessage = g_strdup_vprintf (cMessageFormat, args);
921 	gldi_dialog_set_message (pDialog, cMessage);
922 	g_free (cMessage);
923 	va_end (args);
924 }
925 
gldi_dialog_reload(CairoDialog * pDialog)926 void gldi_dialog_reload (CairoDialog *pDialog)
927 {
928 	// re-set the GTK style class (global style may have changed between system / custom)
929 	GtkStyleContext *ctx = gtk_widget_get_style_context (pDialog->pWidgetLayout);
930 
931 	gtk_style_context_remove_class (ctx, GTK_STYLE_CLASS_MENUITEM);
932 	gtk_style_context_remove_class (ctx, "gldimenuitem");
933 
934 	gtk_style_context_add_class (ctx, myDialogsParam.bUseDefaultColors && myStyleParam.bUseSystemColors ? GTK_STYLE_CLASS_MENUITEM : "gldimenuitem");
935 
936 	// reload the text buffer (color or font may have changed)
937 	if (pDialog->cText != NULL)
938 	{
939 		gchar *cText = pDialog->cText;
940 		pDialog->cText = NULL;
941 		gldi_dialog_set_message (pDialog, cText);
942 		g_free (cText);
943 	}
944 
945 	// reload sizes (radius or linewidth may have changed)
946 	_compute_dialog_sizes (pDialog);
947 }
948