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/>.
20
/******************************************************************************
22
This file is a part of the cairo-dock program,
23
released under the terms of the GNU General Public License.
25
Written by Fabrice Rey (for any bug report, please mail me to fabounet@users.berlios.de)
27
******************************************************************************/
33
#include "applet-struct.h"
34
#include "applet-notifications.h"
35
#include "applet-theme.h"
36
#include "applet-animation.h"
39
void penguin_move_in_dock (CairoDockModuleInstance *myApplet)
41
static GdkRectangle area;
42
if (! cairo_dock_animation_will_be_visible (myDock))
45
PenguinAnimation *pAnimation = penguin_get_current_animation ();
46
g_return_if_fail (pAnimation != NULL);
47
int iPreviousPositionX = myData.iCurrentPositionX, iPreviousPositionY = myData.iCurrentPositionY;
49
Icon *pFirstDrawnIcon = NULL;
50
if (myDock->pFirstDrawnElement != NULL)
51
pFirstDrawnIcon = myDock->pFirstDrawnElement->data;
52
if (pFirstDrawnIcon == NULL && myDock->icons != NULL)
53
pFirstDrawnIcon = myDock->icons->data;
54
int iXMin = (pFirstDrawnIcon != NULL ? pFirstDrawnIcon->fXAtRest : 0);
55
int iXMax = iXMin + myDock->fFlatDockWidth;
56
int iHeight = myDock->iCurrentHeight;
58
penguin_calculate_new_position (myApplet, pAnimation, iXMin, iXMax, iHeight);
60
area.x = (int) ((myDock->iCurrentWidth - myDock->fFlatDockWidth) / 2 + MIN (iPreviousPositionX, myData.iCurrentPositionX));
61
area.y = myDock->iCurrentHeight - MAX (iPreviousPositionY, myData.iCurrentPositionY) - pAnimation->iFrameHeight;
62
area.width = abs (iPreviousPositionX - myData.iCurrentPositionX) + pAnimation->iFrameWidth;
63
area.height = abs (iPreviousPositionY - myData.iCurrentPositionY) + pAnimation->iFrameHeight;
65
cairo_dock_redraw_container_area (myContainer, &area);
67
penguin_advance_to_next_frame (myApplet, pAnimation);
70
static void _penguin_draw_texture (CairoDockModuleInstance *myApplet, PenguinAnimation *pAnimation, double fOffsetX, double fOffsetY, double fScale)
72
g_return_if_fail (pAnimation->iTexture != 0);
73
int iIconWidth, iIconHeight;
74
cairo_dock_get_icon_extent (myIcon, myContainer, &iIconWidth, &iIconHeight);
76
_cairo_dock_enable_texture ();
77
_cairo_dock_set_blend_alpha ();
78
_cairo_dock_set_alpha (1.);
80
glBindTexture (GL_TEXTURE_2D, pAnimation->iTexture);
81
_cairo_dock_apply_current_texture_portion_at_size_with_offset (1.*myData.iCurrentFrame/pAnimation->iNbFrames,
82
.5*myData.iCurrentDirection, 1./pAnimation->iNbFrames, 1./pAnimation->iNbDirections,
83
pAnimation->iFrameWidth*fScale, pAnimation->iFrameHeight*fScale,
84
fOffsetX + myData.iCurrentPositionX, fOffsetY + myData.iCurrentPositionY + pAnimation->iFrameHeight*fScale/2);
85
_cairo_dock_disable_texture ();
87
/*glEnable (GL_SCISSOR_TEST);
88
glScissor ((fOffsetX + myData.iCurrentPositionX) * fScale,
89
(fOffsetY * fScale + myData.iCurrentPositionY) * fScale,
90
pAnimation->iFrameWidth * fScale,
91
pAnimation->iFrameHeight * fScale);
93
glTranslatef ((fOffsetX + myData.iCurrentPositionX + pAnimation->iFrameWidth * (.5 * pAnimation->iNbFrames - myData.iCurrentFrame)) * fScale,
94
(fOffsetY * fScale + myData.iCurrentPositionY + pAnimation->iFrameHeight * (-.5 * pAnimation->iNbDirections + 1 + (myData.iCurrentDirection)) * fScale),
97
glColor4f (1., 1., 1., 1.);
98
cairo_dock_draw_texture (pAnimation->iTexture,
99
pAnimation->iFrameWidth * pAnimation->iNbFrames * fScale,
100
pAnimation->iFrameHeight * pAnimation->iNbDirections * fScale);
102
glDisable (GL_SCISSOR_TEST);*/
104
void penguin_draw_on_dock_opengl (CairoDockModuleInstance *myApplet, CairoContainer *pContainer)
106
PenguinAnimation *pAnimation = penguin_get_current_animation ();
107
if (pAnimation == NULL)
113
_penguin_draw_texture (myApplet, pAnimation, (myDock->iCurrentWidth - myDock->fFlatDockWidth) * .5, 0., 1.);
118
void penguin_draw_on_dock (CairoDockModuleInstance *myApplet, CairoContainer *pContainer, cairo_t *pCairoContext)
120
PenguinAnimation *pAnimation = penguin_get_current_animation ();
121
if (pAnimation == NULL)
124
g_return_if_fail (pAnimation->pSurfaces != NULL);
125
cairo_surface_t *pSurface = pAnimation->pSurfaces[myData.iCurrentDirection][myData.iCurrentFrame];
127
cairo_save (pCairoContext);
128
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
129
cairo_translate (pCairoContext, floor ((myDock->iCurrentWidth - myDock->fFlatDockWidth) / 2 + myData.iCurrentPositionX), myDock->iCurrentHeight - myData.iCurrentPositionY - pAnimation->iFrameHeight);
130
cairo_set_source_surface (pCairoContext, pSurface, 0.0, 0.0);
131
cairo_paint (pCairoContext);
132
cairo_restore (pCairoContext);
134
gboolean penguin_render_on_container (CairoDockModuleInstance *myApplet, CairoContainer *pContainer, cairo_t *pCairoContext)
136
if (pContainer != myContainer)
137
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
138
if (! cairo_dock_animation_will_be_visible (myDock))
139
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
141
if (pCairoContext != NULL)
142
penguin_draw_on_dock (myApplet, pContainer, pCairoContext);
144
penguin_draw_on_dock_opengl (myApplet, pContainer);
145
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
150
void penguin_move_in_icon (CairoDockModuleInstance *myApplet)
152
if (! cairo_dock_animation_will_be_visible (myDock))
155
PenguinAnimation *pAnimation = penguin_get_current_animation ();
156
g_return_if_fail (pAnimation != NULL);
158
double fScale = (pAnimation->iNbFrames > 1 || pAnimation->iSpeed != 0 || pAnimation->iAcceleration != 0 ? myIcon->fScale : 1.); // s'il est a l'arret on le met a la taille de l'icone au repos.
159
int iWidth = myIcon->fWidth / myDock->fRatio * fScale;
160
int iHeight = myIcon->fHeight / myDock->fRatio * fScale;
161
int iXMin = - iWidth / 2;
164
penguin_calculate_new_position (myApplet, pAnimation, iXMin, iXMax, iHeight);
166
if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
168
if (! cairo_dock_begin_draw_icon (myIcon, myContainer))
171
int iIconWidth, iIconHeight;
172
cairo_dock_get_icon_extent (myIcon, myContainer, &iIconWidth, &iIconHeight);
174
g_return_if_fail (pAnimation->iTexture != 0);
175
double f = (1 + g_fAmplitude) / fScale;
176
double x, y; // centre du pingouin, en coordonnƩes absolues.
177
x = myData.iCurrentPositionX - iXMin - iIconWidth/2 + pAnimation->iFrameWidth/2*f;
178
y = myData.iCurrentPositionY + pAnimation->iFrameHeight/2*f;
180
_cairo_dock_enable_texture ();
181
_cairo_dock_set_blend_alpha ();
182
_cairo_dock_set_alpha (1.);
184
glBindTexture (GL_TEXTURE_2D, pAnimation->iTexture);
185
_cairo_dock_apply_current_texture_portion_at_size_with_offset (1.*myData.iCurrentFrame/pAnimation->iNbFrames,
186
.5*myData.iCurrentDirection, 1./pAnimation->iNbFrames, 1./pAnimation->iNbDirections,
187
pAnimation->iFrameWidth*f, pAnimation->iFrameHeight*f,
188
x, - iIconHeight/2 + y);
189
_cairo_dock_disable_texture ();
191
cairo_dock_end_draw_icon (myIcon, myContainer);
195
g_return_if_fail (pAnimation->pSurfaces != NULL);
196
cairo_surface_t *pSurface = pAnimation->pSurfaces[myData.iCurrentDirection][myData.iCurrentFrame];
197
g_return_if_fail (pSurface != NULL);
199
//\________________ On efface l'ancienne image.
200
cairo_set_source_rgba (myDrawContext, 0.0, 0.0, 0.0, 0.0);
201
cairo_set_operator (myDrawContext, CAIRO_OPERATOR_SOURCE);
202
cairo_paint (myDrawContext);
203
cairo_set_operator (myDrawContext, CAIRO_OPERATOR_OVER);
205
//\________________ On applique la nouvelle image.
206
if (pSurface != NULL)
208
cairo_save (myDrawContext);
209
cairo_scale (myDrawContext, (1 + g_fAmplitude) / fScale, (1 + g_fAmplitude) / fScale);
210
cairo_set_source_surface (
213
iXMax + myData.iCurrentPositionX,
214
iHeight - myData.iCurrentPositionY - pAnimation->iFrameHeight);
215
cairo_paint (myDrawContext);
216
cairo_restore (myDrawContext);
219
//\________________ les reflets.
220
CD_APPLET_UPDATE_REFLECT_ON_MY_ICON;
223
CD_APPLET_REDRAW_MY_ICON;
225
penguin_advance_to_next_frame (myApplet, pAnimation);
230
void penguin_calculate_new_position (CairoDockModuleInstance *myApplet, PenguinAnimation *pAnimation, int iXMin, int iXMax, int iHeight)
232
//\________________ On calule la nouvelle vitesse.
233
if (pAnimation->iAcceleration != 0 && myData.iCurrentSpeed != pAnimation->iTerminalVelocity)
235
myData.iCurrentSpeed += pAnimation->iAcceleration;
236
if ( (pAnimation->iAcceleration > 0 && myData.iCurrentSpeed > pAnimation->iTerminalVelocity) || (pAnimation->iAcceleration < 0 && myData.iCurrentSpeed < pAnimation->iTerminalVelocity))
237
myData.iCurrentSpeed = pAnimation->iTerminalVelocity;
240
//\________________ On calule la nouvelle position.
242
if (pAnimation->iDirection == PENGUIN_HORIZONTAL)
244
sens = (myData.iCurrentDirection == 0 ? -1 : 1);
245
myData.iCurrentPositionX += sens * myData.iCurrentSpeed;
249
sens = (pAnimation->iDirection == PENGUIN_UP ? 1 : -1);
250
myData.iCurrentPositionY += sens * myData.iCurrentSpeed;
253
//\________________ On tient compte des contraintes.
254
if (myData.iCurrentPositionX < iXMin || myData.iCurrentPositionX + pAnimation->iFrameWidth > iXMax)
256
if (myData.iCurrentPositionX < iXMin)
257
myData.iCurrentPositionX = iXMin;
259
myData.iCurrentPositionX = iXMax - pAnimation->iFrameWidth;
260
if (pAnimation->iDirection == PENGUIN_HORIZONTAL && myConfig.bFree) // dans l'icone on continue l'animation.
262
if (pAnimation->iNbDirections == 2) // on peut repartir dans l'autre sens ou remonter.
264
int iRandom = g_random_int_range (0, 3);
265
if (iRandom == 0) // 1 chance sur 3.
267
myData.iCurrentDirection = 1 - myData.iCurrentDirection;
268
cd_debug ("myData.iCurrentDirection <- %d", myData.iCurrentDirection);
272
int iNewAnimation = penguin_choose_go_up_animation (myApplet);
273
penguin_set_new_animation (myApplet, iNewAnimation);
278
int iNewAnimation = penguin_choose_go_up_animation (myApplet);
279
penguin_set_new_animation (myApplet, iNewAnimation);
284
if (myData.iCurrentPositionY < (myConfig.bFree ? myBackground.iDockLineWidth + myConfig.iGroundOffset : 0))
286
myData.iCurrentPositionY = (myConfig.bFree ? myBackground.iDockLineWidth + myConfig.iGroundOffset : 0);
288
else if (myData.iCurrentPositionY + pAnimation->iFrameHeight > iHeight)
290
myData.iCurrentPositionY = iHeight - pAnimation->iFrameHeight;
296
void penguin_advance_to_next_frame (CairoDockModuleInstance *myApplet, PenguinAnimation *pAnimation)
298
myData.iCurrentFrame ++;
299
if (myData.iCurrentFrame >= pAnimation->iNbFrames)
301
myData.iCurrentFrame = 0;
303
if (( myData.iCount * myData.fFrameDelay * pAnimation->iNbFrames > myConfig.iDelayBetweenChanges) || pAnimation->bEnding) // il est temps de changer d'animation.
305
if (pAnimation->bEnding)
307
myData.iSleepingTime = 0;
308
if (! myConfig.bFree)
310
cairo_save (myDrawContext); // on n'utilise pas CD_APPLET_SET_SURFACE_ON_MY_ICON (NULL) car il nous cree le pFullIconBuffer qui apres ecrase notre dessin.
311
cairo_set_operator (myDrawContext, CAIRO_OPERATOR_SOURCE);
312
cairo_set_source_rgba (
315
cairo_paint (myDrawContext);
316
cairo_restore (myDrawContext);
318
if (myIcon->pReflectionBuffer != NULL)
320
cairo_surface_destroy (myIcon->pReflectionBuffer);
321
myIcon->pReflectionBuffer = NULL;
323
if (CAIRO_DOCK_CONTAINER_IS_OPENGL (myContainer))
324
cairo_dock_update_icon_texture (myIcon);
326
CD_APPLET_REDRAW_MY_ICON;
328
else // on reste sur la derniere image de l'animation de fin.
330
myData.iCurrentFrame = pAnimation->iNbFrames - 1;
333
penguin_start_animating_with_delay (myApplet);
337
int iNewAnimation = penguin_choose_next_animation (myApplet, pAnimation);
338
penguin_set_new_animation (myApplet, iNewAnimation);
346
int penguin_choose_movement_animation (CairoDockModuleInstance *myApplet)
349
if (myData.iNbMovmentAnimations == 0)
353
int iRandom = g_random_int_range (0, myData.iNbMovmentAnimations); // [a;b[
354
//g_print ( "0<%d<%d => %d\n", iRandom, myData.iNbMovmentAnimations, myData.pMovmentAnimations[iRandom]);
355
return myData.pMovmentAnimations[iRandom];
359
int penguin_choose_go_up_animation (CairoDockModuleInstance *myApplet)
362
if (myData.iNbGoUpAnimations == 0)
363
return penguin_choose_movement_animation (myApplet);
366
int iRandom = g_random_int_range (0, myData.iNbGoUpAnimations); // [a;b[
367
//g_print ( "0<%d<%d => %d\n", iRandom, myData.iNbGoUpAnimations, myData.pGoUpAnimations[iRandom]);
368
return myData.pGoUpAnimations[iRandom];
372
int penguin_choose_beginning_animation (CairoDockModuleInstance *myApplet)
375
if (myData.iNbBeginningAnimations == 0)
376
return penguin_choose_movement_animation (myApplet);
379
int iRandom = g_random_int_range (0, myData.iNbBeginningAnimations); // [a;b[
380
//g_print ( "0<%d<%d => %d\n", iRandom, myData.iNbBeginningAnimations, myData.pBeginningAnimations[iRandom]);
381
return myData.pBeginningAnimations[iRandom];
385
int penguin_choose_ending_animation (CairoDockModuleInstance *myApplet)
388
if (myData.iNbEndingAnimations == 0)
389
return penguin_choose_go_up_animation (myApplet);
392
int iRandom = g_random_int_range (0, myData.iNbEndingAnimations); // [a;b[
393
//g_print ( "0<%d<%d => %d\n", iRandom, myData.iNbEndingAnimations, myData.pEndingAnimations[iRandom]);
394
return myData.pEndingAnimations[iRandom];
398
int penguin_choose_resting_animation (CairoDockModuleInstance *myApplet)
401
if (myData.iNbRestAnimations == 0)
402
return penguin_choose_go_up_animation (myApplet);
405
int iRandom = g_random_int_range (0, myData.iNbRestAnimations); // [a;b[
406
//g_print ( "0<%d<%d => %d\n", iRandom, myData.iNbRestAnimations, myData.pRestAnimations[iRandom]);
407
return myData.pRestAnimations[iRandom];
411
int penguin_choose_next_animation (CairoDockModuleInstance *myApplet, PenguinAnimation *pAnimation)
415
if (pAnimation == NULL || pAnimation->bEnding) // le pingouin est en fin d'animation, on le relance.
417
iNewAnimation = penguin_choose_beginning_animation (myApplet);
419
else if (pAnimation->iDirection == PENGUIN_HORIZONTAL) // le pingouin se deplace.
422
iNewAnimation = penguin_choose_movement_animation (myApplet);
423
else // dans l'icone on ne repart pas en haut sur les bords.
425
int iRandom = g_random_int_range (0, 3);
427
iNewAnimation = penguin_choose_go_up_animation (myApplet);
429
iNewAnimation = penguin_choose_movement_animation (myApplet);
432
else // le pingouin monte ou descend.
434
if (pAnimation->iDirection == PENGUIN_UP) // il monte, on le refait descendre.
435
iNewAnimation = penguin_choose_beginning_animation (myApplet);
436
else // il descend, on le fait se deplacer.
437
iNewAnimation = penguin_choose_movement_animation (myApplet);
439
return iNewAnimation;
443
void penguin_set_new_animation (CairoDockModuleInstance *myApplet, int iNewAnimation)
445
cd_message ("%s (%d)", __func__, iNewAnimation);
446
PenguinAnimation *pPreviousAnimation = penguin_get_current_animation ();
447
int iPreviousWidth = (pPreviousAnimation != NULL ? pPreviousAnimation->iFrameWidth : 0);
448
int iPreviousHeight = (pPreviousAnimation != NULL ? pPreviousAnimation->iFrameHeight : 0);
449
int iPreviousDirection = (pPreviousAnimation != NULL ? pPreviousAnimation->iDirection : 0);
451
myData.iCurrentAnimation = iNewAnimation;
452
myData.iCurrentFrame = 0;
454
PenguinAnimation *pAnimation = penguin_get_current_animation ();
455
if (pAnimation == NULL)
457
myData.iCurrentSpeed = pAnimation->iSpeed;
459
if (pAnimation->pSurfaces == NULL && pAnimation->iTexture == 0)
461
penguin_load_animation_buffer (pAnimation, myDrawContext, myConfig.fAlpha, CAIRO_DOCK_CONTAINER_IS_OPENGL (myContainer));
464
if (pAnimation->iDirection == PENGUIN_HORIZONTAL)
466
if (pAnimation->iNbDirections == 2)
467
myData.iCurrentDirection = g_random_int_range (0, 2); // [a;b[
469
myData.iCurrentDirection = 0;
470
myData.iCurrentPositionY = (myConfig.bFree ? myBackground.iDockLineWidth + myConfig.iGroundOffset : 0);
472
else // la direction reste la meme.
474
myData.iCurrentDirection = MIN (myData.iCurrentDirection, pAnimation->iNbDirections - 1);
475
if (myData.iCurrentDirection == 1) // on plaque a droite.
476
myData.iCurrentPositionX += iPreviousWidth - pAnimation->iFrameWidth;
477
if (pAnimation->iDirection == PENGUIN_DOWN)
480
myData.iCurrentPositionY = myContainer->iHeight;
482
myData.iCurrentPositionY = myIcon->fHeight / myDock->fRatio * myIcon->fScale;
488
gboolean penguin_update_container (CairoDockModuleInstance *myApplet, CairoContainer *pContainer, gboolean *bContinueAnimation)
490
if (pContainer != myContainer)
491
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
493
penguin_move_in_dock (myApplet);
494
*bContinueAnimation = TRUE;
495
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
498
gboolean penguin_update_icon (CairoDockModuleInstance *myApplet, Icon *pIcon, CairoContainer *pContainer, gboolean *bContinueAnimation)
501
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
503
penguin_move_in_icon (myApplet);
504
*bContinueAnimation = TRUE;
505
return CAIRO_DOCK_LET_PASS_NOTIFICATION;
509
void penguin_start_animating (CairoDockModuleInstance *myApplet)
511
int iNewAnimation = penguin_choose_beginning_animation (myApplet);
512
penguin_set_new_animation (myApplet, iNewAnimation);
514
cairo_dock_remove_notification_func (CAIRO_DOCK_UPDATE_ICON_SLOW, (CairoDockNotificationFunc) penguin_update_icon, myApplet);
515
cairo_dock_remove_notification_func (CAIRO_DOCK_UPDATE_DOCK_SLOW, (CairoDockNotificationFunc) penguin_update_container, myApplet);
516
cairo_dock_remove_notification_func (CAIRO_DOCK_RENDER_DOCK, (CairoDockNotificationFunc) penguin_render_on_container, myApplet);
519
cairo_dock_register_notification (CAIRO_DOCK_UPDATE_DOCK_SLOW, (CairoDockNotificationFunc) penguin_update_container, CAIRO_DOCK_RUN_AFTER, myApplet);
520
cairo_dock_register_notification (CAIRO_DOCK_RENDER_DOCK, (CairoDockNotificationFunc) penguin_render_on_container, CAIRO_DOCK_RUN_AFTER, myApplet);
524
cairo_dock_register_notification (CAIRO_DOCK_UPDATE_ICON_SLOW, (CairoDockNotificationFunc) penguin_update_icon, CAIRO_DOCK_RUN_AFTER, myApplet);
528
static gboolean _penguin_restart_delayed (CairoDockModuleInstance *myApplet)
530
myData.iSidRestartDelayed = 0;
531
penguin_start_animating (myApplet);
533
if (! myData.bHasBeenStarted)
535
myData.bHasBeenStarted = TRUE;
536
cd_message ("le pingouin demarre pour la 1ere fois");
538
if (myConfig.bFree) // attention : c'est un hack moyen; il faudrait pouvoir indiquer a cairo-dock de ne pas inserer notre icone...
540
cairo_dock_detach_icon_from_dock (myIcon, myDock, myIcons.bUseSeparator);
541
cairo_dock_update_dock_size (myDock);
545
cairo_dock_insert_icon_in_dock (myIcon, myDock, CAIRO_DOCK_UPDATE_DOCK_SIZE, ! CAIRO_DOCK_ANIMATE_ICON);
551
void penguin_start_animating_with_delay (CairoDockModuleInstance *myApplet)
553
if (myData.iSidRestartDelayed != 0)
555
if (cairo_dock_is_loading ())
557
myData.iSidRestartDelayed = g_timeout_add_seconds (2, (GSourceFunc) _penguin_restart_delayed, (gpointer) myApplet); // priorite au chargement du dock, on demarrera plus tard.
561
myData.iSidRestartDelayed = g_timeout_add_seconds (1, (GSourceFunc) _penguin_restart_delayed, (gpointer) myApplet); // on est oblige de faire ca, pour detacher l'icone apres que le dock l'ait inseree.
562
//myData.iSidRestartDelayed = g_idle_add ((GSourceFunc) _penguin_restart_delayed, (gpointer) myApplet); // on est oblige de faire ca, pour detacher l'icone apres que le dock l'ait inseree.