Bug 376238 - "drag feedback should be transparent on gtk" [p=ventnor.bugzilla@yahoo.com.au (Michael Ventnor) r+sr=roc]

This commit is contained in:
Michael Ventnor 2008-06-16 23:15:40 -07:00
parent 9ef27ae6f1
commit 41defd3c5d
4 changed files with 102 additions and 19 deletions

View File

@ -58,12 +58,17 @@
#include "nsCRT.h"
#include "gfxASurface.h"
#include "gfxXlibSurface.h"
#include "gfxContext.h"
#include "nsImageToPixbuf.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsIDocument.h"
#include "nsISelection.h"
// This sets how opaque the drag image is
#define DRAG_IMAGE_ALPHA_LEVEL 0.5
static PRLogModuleInfo *sDragLm = NULL;
static const char gMimeListType[] = "application/x-moz-internal-item-list";
@ -202,27 +207,34 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
1,
&event);
GdkPixbuf* dragPixbuf = nsnull;
PRBool needsFallbackIcon = PR_FALSE;
nsRect dragRect;
nsPresContext* pc;
if (mHasImage || mSelection) {
nsRefPtr<gfxASurface> surface;
if (mHasImage || mSelection) {
DrawDrag(aDOMNode, aRegion, mScreenX, mScreenY,
&dragRect, getter_AddRefs(surface), &pc);
if (surface) {
dragPixbuf =
nsImageToPixbuf::SurfaceToPixbuf(surface, dragRect.width, dragRect.height);
}
}
if (dragPixbuf) {
if (surface) {
PRInt32 sx = mScreenX, sy = mScreenY;
ConvertToUnscaledDevPixels(pc, &sx, &sy);
gtk_drag_set_icon_pixbuf(context, dragPixbuf,
sx - NSToIntRound(dragRect.x),
sy - NSToIntRound(dragRect.y));
}
PRInt32 offsetX = sx - NSToIntRound(dragRect.x);
PRInt32 offsetY = sy - NSToIntRound(dragRect.y);
if (!SetAlphaPixmap(surface, context, offsetX, offsetY, dragRect)) {
GdkPixbuf* dragPixbuf =
nsImageToPixbuf::SurfaceToPixbuf(surface, dragRect.width, dragRect.height);
if (dragPixbuf)
gtk_drag_set_icon_pixbuf(context, dragPixbuf, offsetX, offsetY);
else
needsFallbackIcon = PR_TRUE;
}
} else {
needsFallbackIcon = PR_TRUE;
}
if (needsFallbackIcon)
gtk_drag_set_icon_default(context);
gtk_target_list_unref(sourceList);
@ -231,6 +243,56 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
return NS_OK;
}
PRBool
nsDragService::SetAlphaPixmap(gfxASurface *aSurface,
GdkDragContext *aContext,
PRInt32 aXOffset,
PRInt32 aYOffset,
const nsRect& dragRect)
{
GdkScreen* screen = gtk_widget_get_screen(mHiddenWidget);
// Transparent drag icons need, like a lot of transparency-related things,
// a compositing X window manager
if (!gdk_screen_is_composited(screen))
return PR_FALSE;
GdkColormap* alphaColormap = gdk_screen_get_rgba_colormap(screen);
if (!alphaColormap)
return PR_FALSE;
GdkPixmap* pixmap = gdk_pixmap_new(NULL, dragRect.width, dragRect.height,
gdk_colormap_get_visual(alphaColormap)->depth);
if (!pixmap)
return PR_FALSE;
gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), alphaColormap);
// Make a gfxXlibSurface wrapped around the pixmap to render on
nsRefPtr<gfxASurface> xPixmapSurface =
nsWindow::GetSurfaceForGdkDrawable(GDK_DRAWABLE(pixmap),
dragRect.Size());
if (!xPixmapSurface)
return PR_FALSE;
nsRefPtr<gfxContext> xPixmapCtx = new gfxContext(xPixmapSurface);
// Clear it...
xPixmapCtx->SetOperator(gfxContext::OPERATOR_CLEAR);
xPixmapCtx->Paint();
// ...and paint the drag image with translucency
xPixmapCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
xPixmapCtx->SetSource(aSurface);
xPixmapCtx->Paint(DRAG_IMAGE_ALPHA_LEVEL);
// The drag transaction addrefs the pixmap, so we can just unref it from us here
gtk_drag_set_icon_pixmap(aContext, alphaColormap, pixmap, NULL,
aXOffset, aYOffset);
gdk_pixmap_unref(pixmap);
return PR_TRUE;
}
NS_IMETHODIMP
nsDragService::StartDragSession()
{

View File

@ -142,6 +142,14 @@ private:
// get a list of the sources in gtk's format
GtkTargetList *GetSourceList(void);
// attempts to create a semi-transparent drag image. Returns TRUE if
// successful, FALSE if not
PRBool SetAlphaPixmap(gfxASurface *aPixbuf,
GdkDragContext *aContext,
PRInt32 aXOffset,
PRInt32 aYOffset,
const nsRect& dragRect);
};
#endif // nsDragService_h__

View File

@ -1677,7 +1677,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
GetHasTransparentBackground(translucent);
nsIntRect boundsRect;
GdkPixmap* bufferPixmap = nsnull;
nsRefPtr<gfxXlibSurface> bufferPixmapSurface;
nsRefPtr<gfxASurface> bufferPixmapSurface;
updateRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y,
&boundsRect.width, &boundsRect.height);
@ -1715,13 +1715,8 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
gint depth = gdk_drawable_get_depth(d);
bufferPixmap = gdk_pixmap_new(d, boundsRect.width, boundsRect.height, depth);
if (bufferPixmap) {
GdkVisual* visual = gdk_drawable_get_visual(GDK_DRAWABLE(bufferPixmap));
Visual* XVisual = gdk_x11_visual_get_xvisual(visual);
Display* display = gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(bufferPixmap));
Drawable drawable = gdk_x11_drawable_get_xid(GDK_DRAWABLE(bufferPixmap));
bufferPixmapSurface =
new gfxXlibSurface(display, drawable, XVisual,
gfxIntSize(boundsRect.width, boundsRect.height));
bufferPixmapSurface = GetSurfaceForGdkDrawable(GDK_DRAWABLE(bufferPixmap),
boundsRect.Size());
if (bufferPixmapSurface) {
bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
nsCOMPtr<nsIRenderingContext> newRC;
@ -6180,6 +6175,19 @@ IM_get_input_context(nsWindow *aWindow)
#endif
/* static */ already_AddRefed<gfxASurface>
nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
const nsSize& aSize)
{
GdkVisual* visual = gdk_drawable_get_visual(aDrawable);
Visual* xVisual = gdk_x11_visual_get_xvisual(visual);
Display* xDisplay = gdk_x11_drawable_get_xdisplay(aDrawable);
Drawable xDrawable = gdk_x11_drawable_get_xid(aDrawable);
return new gfxXlibSurface(xDisplay, xDrawable, xVisual,
gfxIntSize(aSize.width, aSize.height));
}
// return the gfxASurface for rendering to this widget
gfxASurface*
nsWindow::GetThebesSurface()

View File

@ -52,6 +52,8 @@
#include "nsITimer.h"
#include "nsWidgetAtoms.h"
#include "gfxASurface.h"
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
@ -364,6 +366,9 @@ public:
gfxASurface *GetThebesSurface();
static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
const nsSize& aSize);
#ifdef ACCESSIBILITY
static PRBool sAccessibilityEnabled;
#endif