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 <math.h>
22
23 #include <cairo.h>
24 #include <gtk/gtk.h>
25 #include <GL/gl.h>
26
27 #include "cairo-dock-icon-facility.h" // cairo_dock_compute_icon_area
28 #include "cairo-dock-dock-facility.h" // cairo_dock_is_hidden
29 #include "cairo-dock-dock-manager.h" // gldi_dock_get
30 #include "cairo-dock-dialog-manager.h"
31 #include "cairo-dock-log.h"
32 #include "cairo-dock-config.h"
33 #include "cairo-dock-utils.h" // cairo_dock_string_is_address
34 #include "cairo-dock-windows-manager.h" // gldi_windows_get_active
35 #include "cairo-dock-opengl.h"
36 #include "cairo-dock-animations.h" // cairo_dock_animation_will_be_visible
37 #include "cairo-dock-desktop-manager.h" // gldi_desktop_get_width
38 #include "cairo-dock-menu.h" // gldi_menu_new
39 #define _MANAGER_DEF_
40 #include "cairo-dock-container.h"
41
42 // public (manager, config, data)
43 GldiContainersParam myContainersParam;
44 GldiManager myContainersMgr;
45 GldiObjectManager myContainerObjectMgr;
46 GldiContainer *g_pPrimaryContainer = NULL;
47 GldiDesktopBackground *g_pFakeTransparencyDesktopBg = NULL;
48
49 // dependancies
50 extern CairoDockGLConfig g_openglConfig;
51 extern gboolean g_bUseOpenGL;
52 extern CairoDockHidingEffect *g_pHidingBackend; // cairo_dock_is_hidden
53 extern CairoDock *g_pMainDock; // for the default dock visibility when composite goes off->on
54
55 // private
56 static gboolean s_bSticky = TRUE;
57 static gboolean s_bInitialOpacity0 = TRUE; // set initial window opacity to 0, to avoid grey rectangles.
58 static gboolean s_bNoComposite = FALSE;
59 static GldiContainerManagerBackend s_backend;
60
61
cairo_dock_set_containers_non_sticky(void)62 void cairo_dock_set_containers_non_sticky (void)
63 {
64 if (g_pPrimaryContainer != NULL)
65 {
66 cd_warning ("this function has to be called before any container is created.");
67 return;
68 }
69 s_bSticky = FALSE;
70 }
71
cairo_dock_disable_containers_opacity(void)72 void cairo_dock_disable_containers_opacity (void)
73 {
74 if (g_pPrimaryContainer != NULL)
75 {
76 cd_warning ("this function has to be called before any container is created.");
77 return;
78 }
79 s_bInitialOpacity0 = FALSE;
80 }
81
82
_prevent_delete(G_GNUC_UNUSED GtkWidget * pWidget,G_GNUC_UNUSED GdkEvent * event,G_GNUC_UNUSED gpointer data)83 static gboolean _prevent_delete (G_GNUC_UNUSED GtkWidget *pWidget, G_GNUC_UNUSED GdkEvent *event, G_GNUC_UNUSED gpointer data)
84 {
85 cd_debug ("No alt+f4");
86 return TRUE; // on empeche les ALT+F4 malheureux.
87 }
88
cairo_dock_set_default_rgba_visual(GtkWidget * pWidget)89 void cairo_dock_set_default_rgba_visual (GtkWidget *pWidget)
90 {
91 GdkScreen* pScreen = gtk_widget_get_screen (pWidget);
92
93 GdkVisual *pGdkVisual = gdk_screen_get_rgba_visual (pScreen);
94 if (pGdkVisual == NULL)
95 pGdkVisual = gdk_screen_get_system_visual (pScreen);
96
97 gtk_widget_set_visual (pWidget, pGdkVisual);
98 }
99
_cairo_default_container_animation_loop(GldiContainer * pContainer)100 static gboolean _cairo_default_container_animation_loop (GldiContainer *pContainer)
101 {
102 gboolean bContinue = FALSE;
103
104 gboolean bUpdateSlowAnimation = FALSE;
105 pContainer->iAnimationStep ++;
106 if (pContainer->iAnimationStep * pContainer->iAnimationDeltaT >= CAIRO_DOCK_MIN_SLOW_DELTA_T)
107 {
108 bUpdateSlowAnimation = TRUE;
109 pContainer->iAnimationStep = 0;
110 pContainer->bKeepSlowAnimation = FALSE;
111 }
112
113 if (bUpdateSlowAnimation)
114 {
115 gldi_object_notify (pContainer, NOTIFICATION_UPDATE_SLOW, pContainer, &pContainer->bKeepSlowAnimation);
116 }
117
118 gldi_object_notify (pContainer, NOTIFICATION_UPDATE, pContainer, &bContinue);
119
120 if (! bContinue && ! pContainer->bKeepSlowAnimation)
121 {
122 pContainer->iSidGLAnimation = 0;
123 return FALSE;
124 }
125 else
126 return TRUE;
127 }
128
_set_opacity(GtkWidget * pWidget,G_GNUC_UNUSED cairo_t * ctx,GldiContainer * pContainer)129 static gboolean _set_opacity (GtkWidget *pWidget, G_GNUC_UNUSED cairo_t *ctx, GldiContainer *pContainer)
130 {
131 if (pContainer->iWidth != 1 ||pContainer->iHeight != 1)
132 {
133 g_signal_handlers_disconnect_by_func (pWidget, _set_opacity, pContainer); // we'll never need to pass here any more, so simply disconnect ourselves.
134 //g_print ("____OPACITY 1 (%dx%d)\n", pContainer->iWidth, pContainer->iHeight);
135 #if GTK_CHECK_VERSION (3, 8, 0)
136 gtk_widget_set_opacity (pWidget, 1.);
137 #else
138 gtk_window_set_opacity (GTK_WINDOW (pWidget), 1.);
139 #endif
140 }
141 return FALSE ;
142 }
143
_remove_background(G_GNUC_UNUSED GtkWidget * pWidget,GldiContainer * pContainer)144 static void _remove_background (G_GNUC_UNUSED GtkWidget *pWidget, GldiContainer *pContainer)
145 {
146 gdk_window_set_background_pattern (gldi_container_get_gdk_window (pContainer), NULL); // window must be realized (shown)
147 }
148
cairo_dock_redraw_container(GldiContainer * pContainer)149 void cairo_dock_redraw_container (GldiContainer *pContainer)
150 {
151 g_return_if_fail (pContainer != NULL);
152 GdkRectangle rect = {0, 0, pContainer->iWidth, pContainer->iHeight};
153 if (! pContainer->bIsHorizontal)
154 {
155 rect.width = pContainer->iHeight;
156 rect.height = pContainer->iWidth;
157 }
158 cairo_dock_redraw_container_area (pContainer, &rect);
159 }
160
_redraw_container_area(GldiContainer * pContainer,GdkRectangle * pArea)161 static inline void _redraw_container_area (GldiContainer *pContainer, GdkRectangle *pArea)
162 {
163 g_return_if_fail (pContainer != NULL);
164 if (! gldi_container_is_visible (pContainer))
165 return ;
166
167 if (pArea->y < 0)
168 pArea->y = 0;
169 if (pContainer->bIsHorizontal && pArea->y + pArea->height > pContainer->iHeight)
170 pArea->height = pContainer->iHeight - pArea->y;
171 else if (! pContainer->bIsHorizontal && pArea->x + pArea->width > pContainer->iHeight)
172 pArea->width = pContainer->iHeight - pArea->x;
173
174 if (pArea->width > 0 && pArea->height > 0)
175 gdk_window_invalidate_rect (gldi_container_get_gdk_window (pContainer), pArea, FALSE);
176 }
177
cairo_dock_redraw_container_area(GldiContainer * pContainer,GdkRectangle * pArea)178 void cairo_dock_redraw_container_area (GldiContainer *pContainer, GdkRectangle *pArea)
179 {
180 if (CAIRO_DOCK_IS_DOCK (pContainer) && ! cairo_dock_animation_will_be_visible (CAIRO_DOCK (pContainer))) // inutile de redessiner.
181 return ;
182 _redraw_container_area (pContainer, pArea);
183 }
184
cairo_dock_redraw_icon(Icon * icon)185 void cairo_dock_redraw_icon (Icon *icon)
186 {
187 g_return_if_fail (icon != NULL);
188 GldiContainer *pContainer = cairo_dock_get_icon_container (icon);
189 g_return_if_fail (pContainer != NULL);
190 GdkRectangle rect;
191 cairo_dock_compute_icon_area (icon, pContainer, &rect);
192
193 if (CAIRO_DOCK_IS_DOCK (pContainer) &&
194 ( (cairo_dock_is_hidden (CAIRO_DOCK (pContainer)) && ! icon->bIsDemandingAttention && ! icon->bAlwaysVisible)
195 || (CAIRO_DOCK (pContainer)->iRefCount != 0 && ! gldi_container_is_visible (pContainer)) ) ) // inutile de redessiner.
196 return ;
197 _redraw_container_area (pContainer, &rect);
198 }
199
200
cairo_dock_allow_widget_to_receive_data(GtkWidget * pWidget,GCallback pCallBack,gpointer data)201 void cairo_dock_allow_widget_to_receive_data (GtkWidget *pWidget, GCallback pCallBack, gpointer data)
202 {
203 // /*GtkTargetEntry pTargetEntry[6] = {0};
204 // pTargetEntry[0].target = (gchar*)"text/*";
205 /* pTargetEntry[0].flags = (GtkTargetFlags) 0;
206 pTargetEntry[0].info = 0;
207 pTargetEntry[1].target = (gchar*)"text/uri-list";
208 pTargetEntry[2].target = (gchar*)"text/plain";
209 pTargetEntry[3].target = (gchar*)"text/plain;charset=UTF-8";
210 pTargetEntry[4].target = (gchar*)"text/directory";
211 pTargetEntry[5].target = (gchar*)"text/html";
212 gtk_drag_dest_set (pWidget,
213 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION, // GTK_DEST_DEFAULT_HIGHLIGHT ne rend pas joli je trouve.
214 pTargetEntry,
215 6,
216 GDK_ACTION_COPY | GDK_ACTION_MOVE); // le 'GDK_ACTION_MOVE' c'est pour KDE.*/
217 gtk_drag_dest_set (pWidget,
218 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION, // GTK_DEST_DEFAULT_HIGHLIGHT ne rend pas joli je trouve.
219 NULL,
220 0,
221 GDK_ACTION_COPY | GDK_ACTION_MOVE); // le 'GDK_ACTION_MOVE' c'est pour KDE.
222 gtk_drag_dest_add_uri_targets (pWidget);
223 gtk_drag_dest_add_text_targets (pWidget);
224
225 g_signal_connect (G_OBJECT (pWidget),
226 "drag_data_received",
227 pCallBack,
228 data);
229 }
230
gldi_container_disable_drop(GldiContainer * pContainer)231 void gldi_container_disable_drop (GldiContainer *pContainer)
232 {
233 gtk_drag_dest_set_target_list (pContainer->pWidget, NULL);
234 }
235
gldi_container_notify_drop_data(GldiContainer * pContainer,gchar * cReceivedData,Icon * pPointedIcon,double fOrder)236 void gldi_container_notify_drop_data (GldiContainer *pContainer, gchar *cReceivedData, Icon *pPointedIcon, double fOrder)
237 {
238 g_return_if_fail (cReceivedData != NULL);
239 gchar *cData = NULL;
240
241 gchar **cStringList = g_strsplit (cReceivedData, "\n", -1);
242 GString *sArg = g_string_new ("");
243 int i=0, j;
244 while (cStringList[i] != NULL)
245 {
246 g_string_assign (sArg, cStringList[i]);
247
248 if (! cairo_dock_string_is_address (cStringList[i]))
249 {
250 j = i + 1;
251 while (cStringList[j] != NULL)
252 {
253 if (cairo_dock_string_is_address (cStringList[j]))
254 break ;
255 g_string_append_printf (sArg, "\n%s", cStringList[j]);
256 j ++;
257 }
258 i = j;
259 }
260 else
261 {
262 cd_debug (" + adresse");
263 if (sArg->str[sArg->len-1] == '\r')
264 {
265 cd_debug ("retour charriot");
266 sArg->str[sArg->len-1] = '\0';
267 }
268 i ++;
269 }
270
271 cData = sArg->str;
272 cd_debug (" notification de drop '%s'", cData);
273 gldi_object_notify (pContainer, NOTIFICATION_DROP_DATA, cData, pPointedIcon, fOrder, pContainer);
274 }
275
276 g_strfreev (cStringList);
277 g_string_free (sArg, TRUE);
278 }
279
280
gldi_container_reserve_space(GldiContainer * pContainer,int left,int right,int top,int bottom,int left_start_y,int left_end_y,int right_start_y,int right_end_y,int top_start_x,int top_end_x,int bottom_start_x,int bottom_end_x)281 void gldi_container_reserve_space (GldiContainer *pContainer, int left, int right, int top, int bottom, int left_start_y, int left_end_y, int right_start_y, int right_end_y, int top_start_x, int top_end_x, int bottom_start_x, int bottom_end_x)
282 {
283 if (s_backend.reserve_space)
284 s_backend.reserve_space (pContainer, left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x);
285 }
286
gldi_container_get_current_desktop_index(GldiContainer * pContainer)287 int gldi_container_get_current_desktop_index (GldiContainer *pContainer)
288 {
289 if (s_backend.get_current_desktop_index)
290 return s_backend.get_current_desktop_index (pContainer);
291 return 0;
292 }
293
gldi_container_move(GldiContainer * pContainer,int iNumDesktop,int iAbsolutePositionX,int iAbsolutePositionY)294 void gldi_container_move (GldiContainer *pContainer, int iNumDesktop, int iAbsolutePositionX, int iAbsolutePositionY)
295 {
296 if (s_backend.move)
297 s_backend.move (pContainer, iNumDesktop, iAbsolutePositionX, iAbsolutePositionY);
298 }
299
gldi_container_is_active(GldiContainer * pContainer)300 gboolean gldi_container_is_active (GldiContainer *pContainer)
301 {
302 if (s_backend.is_active)
303 return s_backend.is_active (pContainer);
304 return FALSE;
305 }
306
gldi_container_present(GldiContainer * pContainer)307 void gldi_container_present (GldiContainer *pContainer)
308 {
309 if (s_backend.present)
310 s_backend.present (pContainer);
311 }
312
gldi_container_manager_register_backend(GldiContainerManagerBackend * pBackend)313 void gldi_container_manager_register_backend (GldiContainerManagerBackend *pBackend)
314 {
315 gpointer *ptr = (gpointer*)&s_backend;
316 gpointer *src = (gpointer*)pBackend;
317 gpointer *src_end = (gpointer*)(pBackend + 1);
318 while (src != src_end)
319 {
320 if (*src != NULL)
321 *ptr = *src;
322 src ++;
323 ptr ++;
324 }
325 }
326
327
cairo_dock_emit_signal_on_container(GldiContainer * pContainer,const gchar * cSignal)328 gboolean cairo_dock_emit_signal_on_container (GldiContainer *pContainer, const gchar *cSignal)
329 {
330 static gboolean bReturn;
331 g_signal_emit_by_name (pContainer->pWidget, cSignal, NULL, &bReturn);
332 return FALSE;
333 }
cairo_dock_emit_leave_signal(GldiContainer * pContainer)334 gboolean cairo_dock_emit_leave_signal (GldiContainer *pContainer)
335 {
336 // actualize the coordinates of the pointer, since they are most probably out-dated (because the mouse has left the dock, or because a right-click generates an event with (0;0) coordinates)
337 gldi_container_update_mouse_position (pContainer);
338 return cairo_dock_emit_signal_on_container (pContainer, "leave-notify-event");
339 }
cairo_dock_emit_enter_signal(GldiContainer * pContainer)340 gboolean cairo_dock_emit_enter_signal (GldiContainer *pContainer)
341 {
342 return cairo_dock_emit_signal_on_container (pContainer, "enter-notify-event");
343 }
344
345
346 static GtkWidget *s_pMenu = NULL; // right-click menu
gldi_container_build_menu(GldiContainer * pContainer,Icon * icon)347 GtkWidget *gldi_container_build_menu (GldiContainer *pContainer, Icon *icon)
348 {
349 if (s_pMenu != NULL)
350 {
351 //g_print ("previous menu still alive\n");
352 gtk_widget_destroy (GTK_WIDGET (s_pMenu)); // -> 's_pMenu' becomes NULL thanks to the weak pointer.
353 }
354 g_return_val_if_fail (pContainer != NULL, NULL);
355
356 //\_________________________ On construit le menu.
357 GtkWidget *menu = gldi_menu_new (icon);
358
359 //\_________________________ On passe la main a ceux qui veulent y rajouter des choses.
360 gboolean bDiscardMenu = FALSE;
361 gldi_object_notify (pContainer, NOTIFICATION_BUILD_CONTAINER_MENU, icon, pContainer, menu, &bDiscardMenu);
362 if (bDiscardMenu)
363 {
364 gtk_widget_destroy (menu);
365 return NULL;
366 }
367
368 gldi_object_notify (pContainer, NOTIFICATION_BUILD_ICON_MENU, icon, pContainer, menu);
369
370 s_pMenu = menu;
371 g_object_add_weak_pointer (G_OBJECT (menu), (gpointer*)&s_pMenu); // will nullify 's_pMenu' as soon as the menu is destroyed.
372 return menu;
373 }
374
375
gldi_container_create_input_shape(GldiContainer * pContainer,int x,int y,int w,int h)376 cairo_region_t *gldi_container_create_input_shape (GldiContainer *pContainer, int x, int y, int w, int h)
377 {
378 if (pContainer->iWidth == 0 || pContainer->iHeight == 0) // very unlikely to happen, but anyway avoid this case.
379 return NULL;
380
381 cairo_rectangle_int_t rect = {x, y, w, h};
382 cairo_region_t *pShapeBitmap = cairo_region_create_rectangle (&rect); // for a more complex shape, we would need to draw it on a cairo_surface_t, and then make it a region with gdk_cairo_region_from_surface().
383
384 return pShapeBitmap;
385 }
386
387
388 ////////////
389 /// INIT ///
390 ////////////
391
392 static CairoDockVisibility s_iPrevVisibility = CAIRO_DOCK_NB_VISI;
_set_visibility(CairoDock * pDock,gpointer data)393 static void _set_visibility (CairoDock *pDock, gpointer data)
394 {
395 gldi_dock_set_visibility (pDock, GPOINTER_TO_INT (data));
396 }
_enable_fake_transparency(void)397 static void _enable_fake_transparency (void)
398 {
399 g_pFakeTransparencyDesktopBg = gldi_desktop_background_get (g_bUseOpenGL);
400 s_bNoComposite = TRUE;
401 s_iPrevVisibility = g_pMainDock->iVisibility;
402 gldi_docks_foreach_root ((GFunc)_set_visibility, GINT_TO_POINTER (CAIRO_DOCK_VISI_KEEP_BELOW)); // set the visibility to 'keep below'; that's the best compromise between accessibility and visual annoyance.
403 }
_on_composited_changed(GdkScreen * pScreen,G_GNUC_UNUSED gpointer data)404 static void _on_composited_changed (GdkScreen *pScreen, G_GNUC_UNUSED gpointer data)
405 {
406 if (!gdk_screen_is_composited (pScreen) || (g_bUseOpenGL && ! g_openglConfig.bAlphaAvailable))
407 {
408 _enable_fake_transparency ();
409 }
410 else // composite is now ON => disable fake transparency
411 {
412 gldi_desktop_background_destroy (g_pFakeTransparencyDesktopBg);
413 s_bNoComposite = FALSE;
414 g_pFakeTransparencyDesktopBg = NULL;
415 if (s_iPrevVisibility < CAIRO_DOCK_NB_VISI)
416 gldi_docks_foreach_root ((GFunc)_set_visibility, GINT_TO_POINTER (s_iPrevVisibility)); // restore the previous visibility.
417 }
418 }
_check_composite_delayed(G_GNUC_UNUSED gpointer data)419 static gboolean _check_composite_delayed (G_GNUC_UNUSED gpointer data)
420 {
421 // if there is a dialogue at startup, there is no main dock, wait a bit more.
422 if (g_pMainDock == NULL)
423 return TRUE;
424
425 GdkScreen *pScreen = gdk_screen_get_default ();
426 if (!gdk_screen_is_composited (pScreen) || (g_bUseOpenGL && ! g_openglConfig.bAlphaAvailable)) // no composite available -> load the desktop background
427 {
428 cd_message ("Composite is not available");
429 /**g_pFakeTransparencyDesktopBg = gldi_desktop_background_get (g_bUseOpenGL); // we don't modify the visibility on startup; if it's the first launch, the user has to notice the problem. and if it's not, just respect his configuration.
430 s_bNoComposite = TRUE;*/
431 _enable_fake_transparency (); // modify the visibility even on startup, because there is no configuration that is really usable except for 'keep-below'
432 }
433 g_signal_connect (pScreen, "composited-changed", G_CALLBACK (_on_composited_changed), NULL);
434 return FALSE;
435 }
init(void)436 static void init (void)
437 {
438 g_timeout_add_seconds (4, _check_composite_delayed, NULL); // we don't want to be annoyed by the activation of the composite on startup
439 }
440
441 //////////////////
442 /// GET CONFIG ///
443 //////////////////
444
get_config(GKeyFile * pKeyFile,GldiContainersParam * pContainersParam)445 static gboolean get_config (GKeyFile *pKeyFile, GldiContainersParam *pContainersParam)
446 {
447 gboolean bFlushConfFileNeeded = FALSE;
448
449 int iRefreshFrequency = cairo_dock_get_integer_key_value (pKeyFile, "System", "opengl anim freq", &bFlushConfFileNeeded, 33, NULL, NULL);
450 pContainersParam->iGLAnimationDeltaT = 1000. / iRefreshFrequency;
451
452 iRefreshFrequency = cairo_dock_get_integer_key_value (pKeyFile, "System", "cairo anim freq", &bFlushConfFileNeeded, 25, NULL, NULL);
453 pContainersParam->iCairoAnimationDeltaT = 1000. / iRefreshFrequency;
454
455 return bFlushConfFileNeeded;
456 }
457
458 ////////////
459 /// LOAD ///
460 ////////////
461
load(void)462 static void load (void)
463 {
464 if (s_bNoComposite)
465 {
466 g_pFakeTransparencyDesktopBg = gldi_desktop_background_get (g_bUseOpenGL);
467 }
468 }
469
470 //////////////
471 /// UNLOAD ///
472 //////////////
473
unload(void)474 static void unload (void)
475 {
476 gldi_desktop_background_destroy (g_pFakeTransparencyDesktopBg); // destroy it, since it will be unloaded anyway by the desktop-manager
477 g_pFakeTransparencyDesktopBg = NULL;
478 }
479
480 ///////////////
481 /// MANAGER ///
482 ///////////////
483
init_object(GldiObject * obj,gpointer attr)484 static void init_object (GldiObject *obj, gpointer attr)
485 {
486 GldiContainer *pContainer = (GldiContainer*)obj;
487 GldiContainerAttr *cattr = (GldiContainerAttr*)attr;
488
489 pContainer->iface.animation_loop = _cairo_default_container_animation_loop;
490 pContainer->fRatio = 1;
491 pContainer->bIsHorizontal = TRUE;
492 pContainer->bDirectionUp = TRUE;
493
494 // create a window
495 GtkWidget* pWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
496 pContainer->pWidget = pWindow;
497 gtk_window_set_default_size (GTK_WINDOW (pWindow), 1, 1); // this should prevent having grey rectangles during the loading, when the window is mapped and rendered by the WM but not yet by us.
498 gtk_window_resize (GTK_WINDOW (pWindow), 1, 1);
499 gtk_widget_set_app_paintable (pWindow, TRUE);
500 gtk_window_set_decorated (GTK_WINDOW (pWindow), FALSE);
501 gtk_window_set_skip_pager_hint (GTK_WINDOW(pWindow), TRUE);
502 gtk_window_set_skip_taskbar_hint (GTK_WINDOW(pWindow), TRUE);
503 if (s_bSticky)
504 gtk_window_stick (GTK_WINDOW (pWindow));
505 g_signal_connect (G_OBJECT (pWindow),
506 "delete-event",
507 G_CALLBACK (_prevent_delete),
508 NULL);
509 gtk_window_get_size (GTK_WINDOW (pWindow), &pContainer->iWidth, &pContainer->iHeight); // it's only the initial size allocated by GTK.
510
511 // set an RGBA visual for cairo or opengl
512 if (g_bUseOpenGL && ! cattr->bNoOpengl)
513 {
514 gldi_gl_container_init (pContainer);
515 pContainer->iAnimationDeltaT = myContainersParam.iGLAnimationDeltaT;
516 }
517 else
518 {
519 cairo_dock_set_default_rgba_visual (pWindow);
520 pContainer->iAnimationDeltaT = myContainersParam.iCairoAnimationDeltaT;
521 }
522 if (pContainer->iAnimationDeltaT == 0)
523 pContainer->iAnimationDeltaT = 30;
524
525 // set the opacity to 0 to avoid seeing grey rectangles until the window is ready to be painted by us.
526 if (s_bInitialOpacity0)
527 {
528 #if GTK_CHECK_VERSION (3, 8, 0)
529 gtk_widget_set_opacity (pWindow, 0.);
530 #else
531 gtk_window_set_opacity (GTK_WINDOW (pWindow), 0.);
532 #endif
533 g_signal_connect (G_OBJECT (pWindow),
534 "draw",
535 G_CALLBACK (_set_opacity),
536 pContainer); // the callback will be removed once it has done its job.
537 }
538 g_signal_connect (G_OBJECT (pWindow),
539 "realize",
540 G_CALLBACK (_remove_background),
541 pContainer);
542
543 // remove the resize grip added by gtk3
544 gtk_window_set_has_resize_grip (GTK_WINDOW(pWindow), FALSE);
545
546 // make it the primary container if it's the first
547 if (g_pPrimaryContainer == NULL)
548 g_pPrimaryContainer = pContainer;
549 }
550
reset_object(GldiObject * obj)551 static void reset_object (GldiObject *obj)
552 {
553 GldiContainer *pContainer = (GldiContainer*)obj;
554
555 // destroy the opengl context
556 gldi_gl_container_finish (pContainer);
557
558 // destroy the window (will remove all signals)
559 gtk_widget_destroy (pContainer->pWidget);
560 pContainer->pWidget = NULL;
561
562 // stop the animation loop
563 if (pContainer->iSidGLAnimation != 0)
564 {
565 g_source_remove (pContainer->iSidGLAnimation);
566 pContainer->iSidGLAnimation = 0;
567 }
568
569 if (g_pPrimaryContainer == pContainer)
570 g_pPrimaryContainer = NULL;
571 }
572
gldi_register_containers_manager(void)573 void gldi_register_containers_manager (void)
574 {
575 // Manager
576 memset (&myContainersMgr, 0, sizeof (GldiManager));
577 gldi_object_init (GLDI_OBJECT(&myContainersMgr), &myManagerObjectMgr, NULL);
578 myContainersMgr.cModuleName = "Containers";
579 // interface
580 myContainersMgr.init = init;
581 myContainersMgr.load = load;
582 myContainersMgr.unload = unload;
583 myContainersMgr.reload = (GldiManagerReloadFunc)NULL;
584 myContainersMgr.get_config = (GldiManagerGetConfigFunc)get_config;
585 myContainersMgr.reset_config = (GldiManagerResetConfigFunc)NULL;
586 // Config
587 myContainersMgr.pConfig = (GldiManagerConfigPtr)&myContainersParam;
588 myContainersMgr.iSizeOfConfig = sizeof (GldiContainersParam);
589 // data
590 myContainersMgr.pData = (GldiManagerDataPtr)NULL;
591 myContainersMgr.iSizeOfData = 0;
592
593 // Object Manager
594 memset (&myContainerObjectMgr, 0, sizeof (GldiObjectManager));
595 myContainerObjectMgr.cName = "Container";
596 myContainerObjectMgr.iObjectSize = sizeof (GldiContainer);
597 // interface
598 myContainerObjectMgr.init_object = init_object;
599 myContainerObjectMgr.reset_object = reset_object;
600 // signals
601 gldi_object_install_notifications (&myContainerObjectMgr, NB_NOTIFICATIONS_CONTAINER);
602 }
603