2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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.
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/>.
23
#include <glib/gstdio.h>
28
#include <glitz-glx.h>
29
#include <cairo-glitz.h>
32
#include "cairo-dock-draw.h"
33
#include "cairo-dock-draw-opengl.h"
34
#include "cairo-dock-icons.h"
35
#include "cairo-dock-file-manager.h"
36
#include "cairo-dock-modules.h"
37
#include "cairo-dock-config.h"
38
#include "cairo-dock-log.h"
39
#include "cairo-dock-desklet.h"
40
#include "cairo-dock-container.h"
41
#include "cairo-dock-surface-factory.h"
42
#include "cairo-dock-callbacks.h"
43
#include "cairo-dock-animations.h"
44
#include "cairo-dock-notifications.h"
45
#include "cairo-dock-internal-system.h"
46
#include "cairo-dock-keyfile-utilities.h"
47
#include "cairo-dock-dock-factory.h"
48
#include "cairo-dock-gui-manager.h"
49
#include "cairo-dock-flying-container.h"
52
#define HAND_HEIGHT 50
53
#define EXPLOSION_NB_FRAMES 10
55
extern CairoDock *g_pMainDock;
56
extern gchar *g_cCurrentLaunchersPath;
57
extern gchar *g_cCurrentThemePath;
58
extern gboolean g_bUseOpenGL;
59
extern int g_iXScreenWidth[2], g_iXScreenHeight[2];
61
static cairo_surface_t *s_pHandSurface = NULL;
62
static GLuint s_iHandTexture = 0;
63
static double s_fHandWidth, s_fHandHeight;
64
static cairo_surface_t *s_pExplosionSurface = NULL;
65
static GLuint s_iExplosionTexture = 0;
66
static double s_fExplosionWidth, s_fExplosionHeight;
68
static void _cairo_dock_load_hand_image (cairo_t *pCairoContext, int iWidth)
70
if (s_pHandSurface != NULL || s_iHandTexture != 0)
73
s_pHandSurface = cairo_dock_create_surface_from_image (CAIRO_DOCK_SHARE_DATA_DIR"/hand.svg",
77
CAIRO_DOCK_KEEP_RATIO,
78
&s_fHandWidth, &s_fHandHeight,
80
if (s_pHandSurface != NULL && g_bUseOpenGL)
82
s_iHandTexture = cairo_dock_create_texture_from_surface (s_pHandSurface);
83
cairo_surface_destroy (s_pHandSurface);
84
s_pHandSurface = NULL;
87
static void _cairo_dock_load_explosion_image (cairo_t *pCairoContext, int iWidth)
89
if (s_pExplosionSurface != NULL || s_iExplosionTexture != 0)
92
gchar *cExplosionFile = g_strdup_printf ("%s/%s", g_cCurrentThemePath, "explosion.png");
93
if (g_file_test (cExplosionFile, G_FILE_TEST_EXISTS))
95
s_pExplosionSurface = cairo_dock_create_surface_for_icon (cExplosionFile,
97
iWidth * EXPLOSION_NB_FRAMES,
102
s_pExplosionSurface = cairo_dock_create_surface_for_icon (CAIRO_DOCK_SHARE_DATA_DIR"/explosion/explosion.png",
104
iWidth * EXPLOSION_NB_FRAMES,
107
g_free (cExplosionFile);
108
s_fExplosionWidth = iWidth;
109
s_fExplosionHeight = iWidth;
110
if (s_pExplosionSurface != NULL && g_bUseOpenGL)
112
s_iExplosionTexture = cairo_dock_create_texture_from_surface (s_pExplosionSurface);
113
cairo_surface_destroy (s_pExplosionSurface);
114
s_pExplosionSurface = NULL;
119
void cairo_dock_unload_flying_container_textures (void)
121
if (s_iHandTexture != 0)
123
_cairo_dock_delete_texture (s_iHandTexture);
126
if (s_iExplosionTexture != 0)
128
_cairo_dock_delete_texture (s_iExplosionTexture);
129
s_iExplosionTexture = 0;
133
gboolean cairo_dock_update_flying_container_notification (gpointer pUserData, CairoFlyingContainer *pFlyingContainer, gboolean *bContinueAnimation)
135
if (pFlyingContainer->container.iAnimationStep > 0)
137
pFlyingContainer->container.iAnimationStep --;
138
if (pFlyingContainer->container.iAnimationStep == 0)
140
*bContinueAnimation = FALSE;
141
return CAIRO_DOCK_INTERCEPT_NOTIFICATION;
144
gtk_widget_queue_draw (pFlyingContainer->container.pWidget);
146
*bContinueAnimation = TRUE;
147
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
150
gboolean cairo_dock_render_flying_container_notification (gpointer pUserData, CairoFlyingContainer *pFlyingContainer, cairo_t *pCairoContext)
152
Icon *pIcon = pFlyingContainer->pIcon;
153
if (pCairoContext != NULL)
157
cairo_save (pCairoContext);
158
cairo_dock_render_one_icon (pIcon, CAIRO_CONTAINER (pFlyingContainer), pCairoContext, 1., TRUE);
159
cairo_restore (pCairoContext);
161
cairo_set_source_surface (pCairoContext, s_pHandSurface, 0., 0.);
162
cairo_paint (pCairoContext);
164
else if (pFlyingContainer->container.iAnimationStep > 0)
167
int y = (pFlyingContainer->container.iHeight - pFlyingContainer->container.iWidth) / 2;
168
int iCurrentFrame = EXPLOSION_NB_FRAMES - pFlyingContainer->container.iAnimationStep;
170
cairo_rectangle (pCairoContext,
175
cairo_clip (pCairoContext);
177
cairo_set_source_surface (pCairoContext,
179
x - (iCurrentFrame * s_fExplosionWidth),
181
cairo_paint (pCairoContext);
189
/*glTranslatef (pFlyingContainer->container.iWidth / 2,
190
pIcon->fHeight * pIcon->fScale/2,
191
- pFlyingContainer->container.iHeight);*/
192
cairo_dock_render_one_icon_opengl (pIcon, CAIRO_CONTAINER (pFlyingContainer), 1., TRUE);
195
glTranslatef (pFlyingContainer->container.iWidth / 2,
196
pFlyingContainer->container.iHeight - s_fHandHeight/2,
198
cairo_dock_draw_texture (s_iHandTexture, s_fHandWidth, s_fHandHeight);
200
else if (pFlyingContainer->container.iAnimationStep > 0)
202
int iCurrentFrame = EXPLOSION_NB_FRAMES - pFlyingContainer->container.iAnimationStep;
204
glTranslatef (pFlyingContainer->container.iWidth/2,
205
pFlyingContainer->container.iHeight/2,
207
glBindTexture (GL_TEXTURE_2D, s_iExplosionTexture);
208
_cairo_dock_enable_texture ();
209
_cairo_dock_set_blend_source ();
210
_cairo_dock_set_alpha (1.);
211
_cairo_dock_apply_current_texture_portion_at_size_with_offset ((double) iCurrentFrame / EXPLOSION_NB_FRAMES, 1.,
212
1. / EXPLOSION_NB_FRAMES, 1.,
213
s_fExplosionWidth, s_fExplosionHeight,
216
_cairo_dock_disable_texture ();
219
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
223
static gboolean on_expose_flying_icon (GtkWidget *pWidget,
224
GdkEventExpose *pExpose,
225
CairoFlyingContainer *pFlyingContainer)
229
GdkGLContext *pGlContext = gtk_widget_get_gl_context (pWidget);
230
GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (pWidget);
231
if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
234
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
237
cairo_dock_apply_desktop_background_opengl (CAIRO_CONTAINER (pFlyingContainer));
239
cairo_dock_notify (CAIRO_DOCK_RENDER_FLYING_CONTAINER, pFlyingContainer, NULL);
241
if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
242
gdk_gl_drawable_swap_buffers (pGlDrawable);
245
gdk_gl_drawable_gl_end (pGlDrawable);
246
if (! pFlyingContainer->pIcon) // plus d'icone, le container va se faire detruire sous peu, on repasse donc sur un contexte qui a plus d'avenir, sinon cela peut invalider les fonctions qui font appel a OpenGL sans definir de contexte (genre cairo_dock_create_texture_from_surface).
248
GdkGLContext *pGlContext = gtk_widget_get_gl_context (g_pMainDock->container.pWidget);
249
GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (g_pMainDock->container.pWidget);
250
if (gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
251
gdk_gl_drawable_gl_end (pGlDrawable);
256
cairo_t *pCairoContext = cairo_dock_create_drawing_context_on_container (CAIRO_CONTAINER (pFlyingContainer));
258
cairo_dock_notify (CAIRO_DOCK_RENDER_FLYING_CONTAINER, pFlyingContainer, pCairoContext);
260
cairo_destroy (pCairoContext);
266
static gboolean on_configure_flying_icon (GtkWidget* pWidget,
267
GdkEventConfigure* pEvent,
268
CairoFlyingContainer *pFlyingContainer)
270
if (pFlyingContainer->container.iWidth != pEvent->width || pFlyingContainer->container.iHeight != pEvent->height)
272
pFlyingContainer->container.iWidth = pEvent->width;
273
pFlyingContainer->container.iHeight = pEvent->height;
277
GdkGLContext* pGlContext = gtk_widget_get_gl_context (pWidget);
278
GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (pWidget);
279
GLsizei w = pEvent->width;
280
GLsizei h = pEvent->height;
281
if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
284
glViewport(0, 0, w, h);
286
cairo_dock_set_ortho_view (w, h);
288
gdk_gl_drawable_gl_end (pGlDrawable);
294
CairoFlyingContainer *cairo_dock_create_flying_container (Icon *pFlyingIcon, CairoDock *pOriginDock, gboolean bDrawHand)
296
g_return_val_if_fail (pFlyingIcon != NULL, NULL);
297
CairoFlyingContainer * pFlyingContainer = g_new0 (CairoFlyingContainer, 1);
298
pFlyingContainer->container.iType = CAIRO_DOCK_TYPE_FLYING_CONTAINER;
299
GtkWidget* pWindow = cairo_dock_create_container_window ();
300
gtk_window_set_keep_above (GTK_WINDOW (pWindow), TRUE);
301
gtk_window_set_title (GTK_WINDOW(pWindow), "cairo-dock-flying-icon");
302
pFlyingContainer->container.pWidget = pWindow;
303
pFlyingContainer->pIcon = pFlyingIcon;
304
pFlyingContainer->container.bIsHorizontal = TRUE;
305
pFlyingContainer->container.bDirectionUp = TRUE;
306
pFlyingContainer->container.fRatio = 1.;
307
pFlyingContainer->container.bUseReflect = FALSE;
308
cairo_dock_set_default_animation_delta_t (pFlyingContainer);
310
g_signal_connect (G_OBJECT (pWindow),
312
G_CALLBACK (on_expose_flying_icon),
314
g_signal_connect (G_OBJECT (pWindow),
316
G_CALLBACK (on_configure_flying_icon),
319
pFlyingContainer->container.bInside = TRUE;
320
pFlyingIcon->bPointed = TRUE;
321
pFlyingIcon->fScale = 1.;
322
pFlyingContainer->container.iWidth = pFlyingIcon->fWidth * pFlyingIcon->fScale * 3.7;
323
pFlyingContainer->container.iHeight = pFlyingIcon->fHeight * pFlyingIcon->fScale + 1.*pFlyingContainer->container.iWidth / HAND_WIDTH * HAND_HEIGHT * .6;
324
pFlyingIcon->fDrawX = (pFlyingContainer->container.iWidth - pFlyingIcon->fWidth * pFlyingIcon->fScale) / 2 * 1.2;
325
pFlyingIcon->fDrawY = pFlyingContainer->container.iHeight - pFlyingIcon->fHeight * pFlyingIcon->fScale;
327
if (pOriginDock->container.bIsHorizontal)
329
pFlyingContainer->container.iWindowPositionX = pOriginDock->container.iWindowPositionX + pOriginDock->container.iMouseX - pFlyingContainer->container.iWidth/2;
330
pFlyingContainer->container.iWindowPositionY = pOriginDock->container.iWindowPositionY + pOriginDock->container.iMouseY - pFlyingContainer->container.iHeight/2;
334
pFlyingContainer->container.iWindowPositionY = pOriginDock->container.iWindowPositionX + pOriginDock->container.iMouseX - pFlyingContainer->container.iWidth/2;
335
pFlyingContainer->container.iWindowPositionX = pOriginDock->container.iWindowPositionY + pOriginDock->container.iMouseY - pFlyingContainer->container.iHeight/2;
337
/*g_print ("%s (%d;%d %dx%d)\n", __func__ pFlyingContainer->container.iWindowPositionX,
338
pFlyingContainer->container.iWindowPositionY,
339
pFlyingContainer->container.iWidth,
340
pFlyingContainer->container.iHeight);*/
341
gdk_window_move_resize (pWindow->window,
342
pFlyingContainer->container.iWindowPositionX,
343
pFlyingContainer->container.iWindowPositionY,
344
pFlyingContainer->container.iWidth,
345
pFlyingContainer->container.iHeight);
346
/*gtk_window_resize (GTK_WINDOW (pWindow),
347
pFlyingContainer->container.iWidth,
348
pFlyingContainer->container.iHeight);
349
gtk_window_move (GTK_WINDOW (pWindow),
350
pFlyingContainer->container.iWindowPositionX,
351
pFlyingContainer->container.iWindowPositionY);*/
352
gtk_window_present (GTK_WINDOW (pWindow));
354
cairo_t *pSourceContext = cairo_dock_create_drawing_context_generic (CAIRO_CONTAINER (pFlyingContainer));
355
_cairo_dock_load_hand_image (pSourceContext, pFlyingContainer->container.iWidth);
356
_cairo_dock_load_explosion_image (pSourceContext, pFlyingContainer->container.iWidth);
357
cairo_destroy (pSourceContext);
359
pFlyingContainer->bDrawHand = bDrawHand;
361
cairo_dock_request_icon_animation (pFlyingIcon, CAIRO_CONTAINER (pFlyingContainer), bDrawHand ? "pulse" : "bounce", 1e6);
362
cairo_dock_launch_animation (CAIRO_CONTAINER (pFlyingContainer)); // au cas ou pas d'animation.
365
int r = gettimeofday (&tv, NULL);
366
pFlyingContainer->fCreationTime = tv.tv_sec + tv.tv_usec * 1e-6;
368
return pFlyingContainer;
371
void cairo_dock_drag_flying_container (CairoFlyingContainer *pFlyingContainer, CairoDock *pOriginDock)
373
if (pOriginDock->container.bIsHorizontal)
375
pFlyingContainer->container.iWindowPositionX = pOriginDock->container.iWindowPositionX + pOriginDock->container.iMouseX - pFlyingContainer->container.iWidth/2;
376
pFlyingContainer->container.iWindowPositionY = pOriginDock->container.iWindowPositionY + pOriginDock->container.iMouseY - pFlyingContainer->container.iHeight/2;
380
pFlyingContainer->container.iWindowPositionY = pOriginDock->container.iWindowPositionX + pOriginDock->container.iMouseX - pFlyingContainer->container.iWidth/2;
381
pFlyingContainer->container.iWindowPositionX = pOriginDock->container.iWindowPositionY + pOriginDock->container.iMouseY - pFlyingContainer->container.iHeight/2;
383
//g_print (" on tire l'icone volante en (%d;%d)\n", pFlyingContainer->container.iWindowPositionX, pFlyingContainer->container.iWindowPositionY);
384
gtk_window_move (GTK_WINDOW (pFlyingContainer->container.pWidget),
385
pFlyingContainer->container.iWindowPositionX,
386
pFlyingContainer->container.iWindowPositionY);
389
void cairo_dock_free_flying_container (CairoFlyingContainer *pFlyingContainer)
391
cd_debug ("%s ()", __func__);
392
gtk_widget_destroy (pFlyingContainer->container.pWidget); // enleve les signaux.
393
if (pFlyingContainer->container.iSidGLAnimation != 0)
394
g_source_remove (pFlyingContainer->container.iSidGLAnimation);
395
g_free (pFlyingContainer);
398
void cairo_dock_terminate_flying_container (CairoFlyingContainer *pFlyingContainer)
400
Icon *pIcon = pFlyingContainer->pIcon;
401
pFlyingContainer->pIcon = NULL;
402
pFlyingContainer->container.iAnimationStep = EXPLOSION_NB_FRAMES+1;
404
if (pIcon->cDesktopFileName != NULL) // c'est un lanceur, ou un separateur manuel, ou un sous-dock.
406
cairo_dock_remove_one_icon_from_dock (NULL, pIcon);
407
cairo_dock_free_icon (pIcon);
409
else if (CAIRO_DOCK_IS_APPLET(pIcon))
411
cd_debug ("le module %s devient un desklet", pIcon->pModuleInstance->cConfFilePath);
413
cairo_dock_stop_icon_animation (pIcon);
414
GError *erreur = NULL;
415
GKeyFile *pKeyFile = cairo_dock_open_key_file (pIcon->pModuleInstance->cConfFilePath);
416
if (pKeyFile != NULL)
418
//\______________ On centre le desklet sur l'icone volante.
419
int iDeskletWidth = cairo_dock_get_integer_key_value (pKeyFile, "Desklet", "width", NULL, 92, NULL, NULL);
420
int iDeskletHeight = cairo_dock_get_integer_key_value (pKeyFile, "Desklet", "height", NULL, 92, NULL, NULL);
422
int iDeskletPositionX = pFlyingContainer->container.iWindowPositionX + (pFlyingContainer->container.iWidth - iDeskletWidth)/2;
423
int iDeskletPositionY = pFlyingContainer->container.iWindowPositionY + (pFlyingContainer->container.iHeight - iDeskletHeight)/2;
425
int iRelativePositionX = (iDeskletPositionX + iDeskletWidth/2 <= g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL]/2 ? iDeskletPositionX : iDeskletPositionX - g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL]);
426
int iRelativePositionY = (iDeskletPositionY + iDeskletHeight/2 <= g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]/2 ? iDeskletPositionY : iDeskletPositionY - g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]);
428
g_key_file_set_boolean (pKeyFile, "Desklet", "initially detached", TRUE);
429
g_key_file_set_double (pKeyFile, "Desklet", "x position", iDeskletPositionX);
430
g_key_file_set_double (pKeyFile, "Desklet", "y position", iDeskletPositionY);
432
cairo_dock_update_desklet_detached_state_in_gui (pIcon->pModuleInstance, TRUE);
433
cairo_dock_update_desklet_position_in_gui (pIcon->pModuleInstance, iDeskletPositionX, iDeskletPositionY);
435
cairo_dock_write_keys_to_file (pKeyFile, pIcon->pModuleInstance->cConfFilePath);
436
g_key_file_free (pKeyFile);
438
//\______________ On detache le module.
439
cairo_dock_reload_module_instance (pIcon->pModuleInstance, TRUE);
441
//\______________ On fait apparaitre le desklet avec un effet de zoom.
442
if (pIcon->pModuleInstance->pDesklet) // normalement toujours vrai.
444
while (pIcon->pModuleInstance->pDesklet->iDesiredWidth != 0 && pIcon->pModuleInstance->pDesklet->iDesiredHeight != 0 && (pIcon->pModuleInstance->pDesklet->iKnownWidth != pIcon->pModuleInstance->pDesklet->iDesiredWidth || pIcon->pModuleInstance->pDesklet->iKnownHeight != pIcon->pModuleInstance->pDesklet->iDesiredHeight))
446
gtk_main_iteration (); // on le laisse se charger en plein.
447
if (! pIcon->pModuleInstance->pDesklet) // ne devrait pas arriver.
450
cairo_dock_zoom_out_desklet (pIcon->pModuleInstance->pDesklet);