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/>.
26
#include <X11/Xatom.h>
27
#include <X11/Xutil.h>
30
#include <X11/extensions/Xcomposite.h>
31
//#include <X11/extensions/Xdamage.h>
34
#include "cairo-dock-load.h"
35
#include "cairo-dock-icons.h"
36
#include "cairo-dock-draw.h"
37
#include "cairo-dock-draw-opengl.h"
38
#include "cairo-dock-dock-factory.h"
39
#include "cairo-dock-dialogs.h"
40
#include "cairo-dock-animations.h"
41
#include "cairo-dock-surface-factory.h"
42
#include "cairo-dock-applications-manager.h"
43
#include "cairo-dock-log.h"
44
#include "cairo-dock-dock-manager.h"
45
#include "cairo-dock-class-manager.h"
46
#include "cairo-dock-X-utilities.h"
47
#include "cairo-dock-internal-taskbar.h"
48
#include "cairo-dock-internal-icons.h"
49
#include "cairo-dock-notifications.h"
50
#include "cairo-dock-launcher-factory.h"
51
#include "cairo-dock-container.h"
52
#include "cairo-dock-dock-factory.h"
53
#include "cairo-dock-dock-facility.h"
54
#include "cairo-dock-callbacks.h"
55
#include "cairo-dock-application-facility.h"
56
#include "cairo-dock-application-factory.h"
58
extern CairoDock *g_pMainDock;
60
static Display *s_XDisplay = NULL;
61
static Atom s_aNetWmIcon;
62
static Atom s_aNetWmState;
63
static Atom s_aNetWmSkipPager;
64
static Atom s_aNetWmSkipTaskbar;
65
static Atom s_aNetWmWindowType;
66
static Atom s_aNetWmWindowTypeNormal;
67
static Atom s_aNetWmWindowTypeDialog;
68
static Atom s_aWmHints;
69
static Atom s_aNetWmHidden;
70
static Atom s_aNetWmFullScreen;
71
static Atom s_aNetWmMaximizedHoriz;
72
static Atom s_aNetWmMaximizedVert;
73
static Atom s_aNetWmDemandsAttention;
76
void cairo_dock_initialize_application_factory (Display *pXDisplay)
78
s_XDisplay = pXDisplay;
79
g_return_if_fail (s_XDisplay != NULL);
81
s_aNetWmIcon = XInternAtom (s_XDisplay, "_NET_WM_ICON", False);
83
s_aNetWmState = XInternAtom (s_XDisplay, "_NET_WM_STATE", False);
84
s_aNetWmSkipPager = XInternAtom (s_XDisplay, "_NET_WM_STATE_SKIP_PAGER", False);
85
s_aNetWmSkipTaskbar = XInternAtom (s_XDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False);
86
s_aNetWmHidden = XInternAtom (s_XDisplay, "_NET_WM_STATE_HIDDEN", False);
88
s_aNetWmWindowType = XInternAtom (s_XDisplay, "_NET_WM_WINDOW_TYPE", False);
89
s_aNetWmWindowTypeNormal = XInternAtom (s_XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False);
90
s_aNetWmWindowTypeDialog = XInternAtom (s_XDisplay, "_NET_WM_WINDOW_TYPE_DIALOG", False);
92
s_aWmHints = XInternAtom (s_XDisplay, "WM_HINTS", False);
94
s_aNetWmFullScreen = XInternAtom (s_XDisplay, "_NET_WM_STATE_FULLSCREEN", False);
95
s_aNetWmMaximizedHoriz = XInternAtom (s_XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
96
s_aNetWmMaximizedVert = XInternAtom (s_XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False);
97
s_aNetWmDemandsAttention = XInternAtom (s_XDisplay, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
100
cairo_surface_t *cairo_dock_create_surface_from_xpixmap (Pixmap Xid, cairo_t *pSourceContext, double fMaxScale, double *fWidth, double *fHeight)
102
g_return_val_if_fail (cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS && Xid > 0, NULL);
103
GdkPixbuf *pPixbuf = cairo_dock_get_pixbuf_from_pixmap (Xid, TRUE);
106
cd_warning ("No thumbnail available.\nEither the WM doesn't support this functionnality, or the window was minimized when the dock has been launched.");
109
cd_debug ("window pixmap : %dx%d", gdk_pixbuf_get_width (pPixbuf), gdk_pixbuf_get_height (pPixbuf));
110
cairo_surface_t *pSurface = cairo_dock_create_surface_from_pixbuf (pPixbuf,
113
myIcons.tIconAuthorizedWidth[CAIRO_DOCK_APPLI],
114
myIcons.tIconAuthorizedHeight[CAIRO_DOCK_APPLI],
115
CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE, // on conserve le ratio de la fenetre, tout en gardant la taille habituelle des icones d'appli.
119
g_object_unref (pPixbuf);
123
cairo_surface_t *cairo_dock_create_surface_from_xwindow (Window Xid, cairo_t *pSourceContext, double fMaxScale, double *fWidth, double *fHeight)
125
g_return_val_if_fail (cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
127
Atom aReturnedType = 0;
128
int aReturnedFormat = 0;
129
unsigned long iLeftBytes, iBufferNbElements = 0;
130
gulong *pXIconBuffer = NULL;
131
XGetWindowProperty (s_XDisplay, Xid, s_aNetWmIcon, 0, G_MAXULONG, False, XA_CARDINAL, &aReturnedType, &aReturnedFormat, &iBufferNbElements, &iLeftBytes, (guchar **)&pXIconBuffer);
133
if (iBufferNbElements > 2)
135
cairo_surface_t *pNewSurface = cairo_dock_create_surface_from_xicon_buffer (pXIconBuffer,
138
myIcons.tIconAuthorizedWidth[CAIRO_DOCK_APPLI],
139
myIcons.tIconAuthorizedHeight[CAIRO_DOCK_APPLI],
142
XFree (pXIconBuffer);
145
else // sinon on tente avec l'icone eventuellement presente dans les WMHints.
147
XWMHints *pWMHints = XGetWMHints (s_XDisplay, Xid);
148
if (pWMHints == NULL)
150
cd_debug (" aucun WMHints");
153
//\__________________ On recupere les donnees dans un pixbuf.
154
GdkPixbuf *pIconPixbuf = NULL;
155
if (pWMHints->flags & IconWindowHint)
157
Window XIconID = pWMHints->icon_window;
158
cd_debug (" pas de _NET_WM_ICON, mais une fenetre (ID:%d)", XIconID);
159
Pixmap iPixmap = cairo_dock_get_window_background_pixmap (XIconID);
160
pIconPixbuf = cairo_dock_get_pixbuf_from_pixmap (iPixmap, TRUE); /// A valider ...
162
else if (pWMHints->flags & IconPixmapHint)
164
cd_debug (" pas de _NET_WM_ICON, mais un pixmap");
165
Pixmap XPixmapID = pWMHints->icon_pixmap;
166
pIconPixbuf = cairo_dock_get_pixbuf_from_pixmap (XPixmapID, TRUE);
168
//\____________________ On lui applique le masque de transparence s'il existe.
169
if (pWMHints->flags & IconMaskHint)
171
Pixmap XPixmapMaskID = pWMHints->icon_mask;
172
GdkPixbuf *pMaskPixbuf = cairo_dock_get_pixbuf_from_pixmap (XPixmapMaskID, FALSE);
174
int iNbChannels = gdk_pixbuf_get_n_channels (pIconPixbuf);
175
int iRowstride = gdk_pixbuf_get_rowstride (pIconPixbuf);
176
guchar *p, *pixels = gdk_pixbuf_get_pixels (pIconPixbuf);
178
int iNbChannelsMask = gdk_pixbuf_get_n_channels (pMaskPixbuf);
179
int iRowstrideMask = gdk_pixbuf_get_rowstride (pMaskPixbuf);
180
guchar *q, *pixelsMask = gdk_pixbuf_get_pixels (pMaskPixbuf);
182
int w = MIN (gdk_pixbuf_get_width (pIconPixbuf), gdk_pixbuf_get_width (pMaskPixbuf));
183
int h = MIN (gdk_pixbuf_get_height (pIconPixbuf), gdk_pixbuf_get_height (pMaskPixbuf));
185
for (y = 0; y < h; y ++)
187
for (x = 0; x < w; x ++)
189
p = pixels + y * iRowstride + x * iNbChannels;
190
q = pixelsMask + y * iRowstrideMask + x * iNbChannelsMask;
198
g_object_unref (pMaskPixbuf);
203
//\____________________ On cree la surface.
204
if (pIconPixbuf != NULL)
206
cairo_surface_t *pNewSurface = cairo_dock_create_surface_from_pixbuf (pIconPixbuf,
209
myIcons.tIconAuthorizedWidth[CAIRO_DOCK_APPLI],
210
myIcons.tIconAuthorizedHeight[CAIRO_DOCK_APPLI],
211
CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
216
g_object_unref (pIconPixbuf);
224
static Window _cairo_dock_get_parent_window (Window Xid)
226
Atom aReturnedType = 0;
227
int aReturnedFormat = 0;
228
unsigned long iLeftBytes, iBufferNbElements = 0;
229
Window *pXBuffer = NULL;
230
XGetWindowProperty (s_XDisplay, Xid, XInternAtom (s_XDisplay, "WM_TRANSIENT_FOR", False), 0, G_MAXULONG, False, XA_WINDOW, &aReturnedType, &aReturnedFormat, &iBufferNbElements, &iLeftBytes, (guchar **)&pXBuffer);
232
Window xParentWindow = (iBufferNbElements > 0 && pXBuffer != NULL ? pXBuffer[0] : 0);
233
if (pXBuffer != NULL)
235
return xParentWindow;
237
Icon * cairo_dock_create_icon_from_xwindow (cairo_t *pSourceContext, Window Xid, CairoDock *pDock)
239
//g_print ("%s (%d)\n", __func__, Xid);
240
guchar *pNameBuffer = NULL;
241
///gulong *pPidBuffer = NULL;
242
Atom aReturnedType = 0;
243
int aReturnedFormat = 0;
244
unsigned long iLeftBytes, iBufferNbElements;
245
cairo_surface_t *pNewSurface = NULL;
246
double fWidth, fHeight;
248
//\__________________ On regarde si on doit l'afficher ou la sauter.
249
gboolean bSkip = FALSE, bIsHidden = FALSE, bIsFullScreen = FALSE, bIsMaximized = FALSE, bDemandsAttention = FALSE;
250
gulong *pXStateBuffer = NULL;
251
iBufferNbElements = 0;
252
XGetWindowProperty (s_XDisplay, Xid, s_aNetWmState, 0, G_MAXULONG, False, XA_ATOM, &aReturnedType, &aReturnedFormat, &iBufferNbElements, &iLeftBytes, (guchar **)&pXStateBuffer);
253
if (iBufferNbElements > 0)
255
guint i, iNbMaximizedDimensions = 0;
256
for (i = 0; i < iBufferNbElements && ! bSkip; i ++)
258
if (pXStateBuffer[i] == s_aNetWmSkipTaskbar)
260
else if (pXStateBuffer[i] == s_aNetWmHidden)
262
else if (pXStateBuffer[i] == s_aNetWmMaximizedVert)
263
iNbMaximizedDimensions ++;
264
else if (pXStateBuffer[i] == s_aNetWmMaximizedHoriz)
265
iNbMaximizedDimensions ++;
266
else if (pXStateBuffer[i] == s_aNetWmFullScreen)
267
bIsFullScreen = TRUE;
268
else if (pXStateBuffer[i] == s_aNetWmDemandsAttention)
269
bDemandsAttention = TRUE;
270
//else if (pXStateBuffer[i] == s_aNetWmSkipPager) // contestable ...
273
bIsMaximized = (iNbMaximizedDimensions == 2);
274
//g_print (" -------- bSkip : %d\n", bSkip);
275
XFree (pXStateBuffer);
279
cd_debug (" cette fenetre est timide");
283
//\__________________ On regarde son type.
284
gulong *pTypeBuffer = NULL;
285
cd_debug (" + nouvelle icone d'appli (%d)", Xid);
286
XGetWindowProperty (s_XDisplay, Xid, s_aNetWmWindowType, 0, G_MAXULONG, False, XA_ATOM, &aReturnedType, &aReturnedFormat, &iBufferNbElements, &iLeftBytes, (guchar **)&pTypeBuffer);
287
if (iBufferNbElements != 0)
289
gboolean bKeep = FALSE;
291
for (i = 0; i < iBufferNbElements; i ++) // The Client SHOULD specify window types in order of preference (the first being most preferable) but MUST include at least one of the basic window type atoms.
293
if (pTypeBuffer[i] == s_aNetWmWindowTypeNormal) // une fenetre normale, on prend.
298
if (pTypeBuffer[i] == s_aNetWmWindowTypeDialog) // on saute si c'est un dialogue modal, sinon on garde.
300
/*Window iPropWindow;
301
XGetTransientForHint (s_XDisplay, Xid, &iPropWindow);
302
g_print ("%s\n", gdk_x11_get_xatom_name (iPropWindow));*/
303
Window XMainAppliWindow = _cairo_dock_get_parent_window (Xid);
304
if (XMainAppliWindow != 0)
306
cd_debug (" dialogue 'transient for %d' => on ignore", XMainAppliWindow);
307
if (bDemandsAttention && (myTaskBar.bDemandsAttentionWithDialog || myTaskBar.cAnimationOnDemandsAttention))
309
Icon *pParentIcon = cairo_dock_get_icon_with_Xid (XMainAppliWindow);
310
if (pParentIcon != NULL)
312
cd_debug ("%s requiert votre attention indirectement !", pParentIcon->cName);
313
cairo_dock_appli_demands_attention (pParentIcon);
316
cd_debug ("ce dialogue est bien bruyant ! (%d)", XMainAppliWindow);
322
} // autre type : on saute.
327
cd_debug ("type indesirable (%d)\n", *pTypeBuffer);
333
Window XMainAppliWindow = 0;
334
XGetTransientForHint (s_XDisplay, Xid, &XMainAppliWindow);
335
if (XMainAppliWindow != 0)
337
cd_debug (" fenetre modale => on saute.");
338
if (bDemandsAttention && (myTaskBar.bDemandsAttentionWithDialog || myTaskBar.cAnimationOnDemandsAttention))
340
Icon *pParentIcon = cairo_dock_get_icon_with_Xid (XMainAppliWindow);
341
if (pParentIcon != NULL)
343
cd_debug ("%s requiert votre attention indirectement !", pParentIcon->cName);
344
cairo_dock_appli_demands_attention (pParentIcon);
347
cd_debug ("ce dialogue est bien bruyant ! (%d)", XMainAppliWindow);
349
return NULL; // meme remarque.
354
//\__________________ On recupere son nom.
355
gchar *cName = cairo_dock_get_xwindow_name (Xid, TRUE);
356
cd_debug ("recuperation de '%s' (bIsHidden : %d)", cName, bIsHidden);
359
//\__________________ On recupere la classe.
360
XClassHint *pClassHint = XAllocClassHint ();
361
gchar *cClass = NULL;
362
if (XGetClassHint (s_XDisplay, Xid, pClassHint) != 0)
364
cd_debug (" res_name : %s(%x); res_class : %s(%x)", pClassHint->res_name, pClassHint->res_name, pClassHint->res_class, pClassHint->res_class);
365
if (pClassHint->res_class && strcmp (pClassHint->res_class, "Wine") == 0 && pClassHint->res_name && g_str_has_suffix (pClassHint->res_name, ".exe"))
367
cd_debug (" wine application detected, changing the class '%s' to '%s'", pClassHint->res_class, pClassHint->res_name);
368
cClass = g_ascii_strdown (pClassHint->res_name, -1);
370
else if (*pClassHint->res_class == '/' && g_str_has_suffix (pClassHint->res_class, ".exe")) // cas des applications Mono telles que tomboy ...
372
gchar *str = strrchr (pClassHint->res_class, '/');
376
str = pClassHint->res_class;
377
cClass = g_ascii_strdown (str, -1);
378
cClass[strlen (cClass) - 4] = '\0';
381
cClass = g_ascii_strdown (pClassHint->res_class, -1); // on la passe en minuscule, car certaines applis ont la bonne idee de donner des classes avec une majuscule ou non suivant les fenetres.
383
cairo_dock_remove_version_from_string (cClass); // on enleve les numeros de version (Openoffice.org-3.1)
385
XFree (pClassHint->res_name);
386
XFree (pClassHint->res_class);
390
cd_warning ("this window doesn't belong to any class, skip it.");
395
//\__________________ On cree, on remplit l'icone, et on l'enregistre, par contre elle sera inseree plus tard.
396
Icon *icon = g_new0 (Icon, 1);
397
icon->iType = CAIRO_DOCK_APPLI;
400
//\__________________ On renseigne les infos en provenance de X.
401
icon->cName = (cName ? cName : g_strdup (cClass));
402
icon->cClass = cClass;
403
icon->bIsHidden = bIsHidden;
404
icon->bIsMaximized = bIsMaximized;
405
icon->bIsFullScreen = bIsFullScreen;
406
icon->bIsDemandingAttention = bDemandsAttention;
407
icon->bHasIndicator = myTaskBar.bDrawIndicatorOnAppli;
408
/**Icon * pLastAppli = cairo_dock_get_last_appli (pDock->icons);
409
icon->fOrder = (pLastAppli != NULL ? pLastAppli->fOrder + 1 : 1);*/
410
icon->fOrder = CAIRO_DOCK_LAST_ORDER;
412
cairo_dock_get_xwindow_geometry (Xid,
413
&icon->windowGeometry.x,
414
&icon->windowGeometry.y,
415
&icon->windowGeometry.width,
416
&icon->windowGeometry.height);
417
icon->iNumDesktop = cairo_dock_get_xwindow_desktop (Xid);
419
if (myTaskBar.iMinimizedWindowRenderType == 1)
421
Display *display = gdk_x11_get_default_xdisplay ();
422
icon->iBackingPixmap = XCompositeNameWindowPixmap (display, Xid);
423
/*icon->iDamageHandle = XDamageCreate (s_XDisplay, Xid, XDamageReportNonEmpty); // XDamageReportRawRectangles
424
g_print ("backing pixmap : %d ; iDamageHandle : %d\n", icon->iBackingPixmap, icon->iDamageHandle);*/
428
//\____________ On remplit ses buffers.
429
cairo_dock_fill_icon_buffers_for_dock (icon, pSourceContext, pDock);
431
if (icon->bIsHidden && myTaskBar.iMinimizedWindowRenderType == 2)
433
cairo_dock_draw_hidden_appli_icon (icon, CAIRO_CONTAINER (pDock), FALSE);
436
//\____________ On enregistre l'appli et on commence a la surveiller.
437
cairo_dock_register_appli (icon);
439
cairo_dock_set_xwindow_mask (Xid, PropertyChangeMask | StructureNotifyMask);