summaryrefslogtreecommitdiff
path: root/src/drivers/X11
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2016-03-10 17:19:34 +0000
committerManolo Gouy <Manolo>2016-03-10 17:19:34 +0000
commitd4768073fa67e7f78872bc80f4dff1dd8aa32f69 (patch)
treee49adba4ced816e851cbb74e5cac4f9a995f4189 /src/drivers/X11
parent79f79d292c8ffe7a172237c614345a7bc667de80 (diff)
Implement non-rectangular windows using the Window Driver mechanism.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11336 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/drivers/X11')
-rw-r--r--src/drivers/X11/Fl_X11_Window_Driver.H15
-rw-r--r--src/drivers/X11/Fl_X11_Window_Driver.cxx112
2 files changed, 124 insertions, 3 deletions
diff --git a/src/drivers/X11/Fl_X11_Window_Driver.H b/src/drivers/X11/Fl_X11_Window_Driver.H
index 36c5b67cb..458d1bd1c 100644
--- a/src/drivers/X11/Fl_X11_Window_Driver.H
+++ b/src/drivers/X11/Fl_X11_Window_Driver.H
@@ -42,15 +42,28 @@
? where do we handle the interface between OpenGL/DirectX and Cocoa/WIN32/Glx?
*/
+struct Fl_Window_Driver::shape_data_type {
+ int lw_; ///< width of shape image
+ int lh_; ///< height of shape image
+ Fl_Image* shape_; ///< shape image
+ Fl_Bitmap *todelete_; ///< auxiliary bitmap image
+};
+
class FL_EXPORT Fl_X11_Window_Driver : public Fl_Window_Driver
{
+ friend class Fl_X;
+private:
+ void combine_mask();
+ void shape_bitmap_(Fl_Image* b);
+ void shape_alpha_(Fl_Image* img, int offset);
public:
Fl_X11_Window_Driver(Fl_Window*);
virtual void take_focus();
+ virtual void shape(const Fl_Image* img);
+ virtual void draw();
};
-
#endif // FL_X11_WINDOW_DRIVER_H
//
diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx
index 10988bd7c..efaa31851 100644
--- a/src/drivers/X11/Fl_X11_Window_Driver.cxx
+++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx
@@ -20,8 +20,16 @@
#include "../../config_lib.h"
#include "Fl_X11_Window_Driver.H"
#include <FL/fl_draw.H>
+#include <string.h>
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#define ShapeBounding 0
+#define ShapeSet 0
+
#if USE_XDBE
#include <X11/extensions/Xdbe.h>
+
static int can_xdbe(); // forward
// class to be used only if Xdbe is used
@@ -31,7 +39,7 @@ public:
virtual int double_flush(int eraseoverlay);
virtual void destroy_double_buffer();
};
-#endif
+#endif // USE_XDBE
Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w)
@@ -68,6 +76,7 @@ static int can_xdbe() { // whether the Xdbe extension is usable
if (!tried) {
tried = 1;
int event_base, error_base;
+ fl_open_display();
if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0;
Drawable root = RootWindow(fl_display,fl_screen);
int numscreens = 1;
@@ -116,9 +125,108 @@ void Fl_X11_Dbe_Window_Driver::destroy_double_buffer() {
XdbeDeallocateBackBufferName(fl_display, i->other_xid);
i->other_xid = 0;
}
-
#endif // USE_XDBE
+
+void Fl_X11_Window_Driver::shape_bitmap_(Fl_Image* b) {
+ shape_data_->shape_ = b;
+}
+
+void Fl_X11_Window_Driver::shape_alpha_(Fl_Image* img, int offset) {
+ int i, j, d = img->d(), w = img->w(), h = img->h(), bytesperrow = (w+7)/8;
+ unsigned u;
+ uchar byte, onebit;
+ // build an Fl_Bitmap covering the non-fully transparent/black part of the image
+ const uchar* bits = new uchar[h*bytesperrow]; // to store the bitmap
+ const uchar* alpha = (const uchar*)*img->data() + offset; // points to alpha value of rgba pixels
+ for (i = 0; i < h; i++) {
+ uchar *p = (uchar*)bits + i * bytesperrow;
+ byte = 0;
+ onebit = 1;
+ for (j = 0; j < w; j++) {
+ if (d == 3) {
+ u = *alpha;
+ u += *(alpha+1);
+ u += *(alpha+2);
+ }
+ else u = *alpha;
+ if (u > 0) { // if the pixel is not fully transparent/black
+ byte |= onebit; // turn on the corresponding bit of the bitmap
+ }
+ onebit = onebit << 1; // move the single set bit one position to the left
+ if (onebit == 0 || j == w-1) {
+ onebit = 1;
+ *p++ = byte; // store in bitmap one pack of bits
+ byte = 0;
+ }
+ alpha += d; // point to alpha value of next pixel
+ }
+ }
+ Fl_Bitmap* bitmap = new Fl_Bitmap(bits, w, h);
+ bitmap->alloc_array = 1;
+ shape_bitmap_(bitmap);
+ shape_data_->todelete_ = bitmap;
+}
+
+void Fl_X11_Window_Driver::shape(const Fl_Image* img) {
+ if (shape_data_) {
+ if (shape_data_->todelete_) { delete shape_data_->todelete_; }
+ }
+ else {
+ shape_data_ = new shape_data_type;
+ }
+ memset(shape_data_, 0, sizeof(shape_data_type));
+ pWindow->border(false);
+ int d = img->d();
+ if (d && img->count() >= 2) shape_pixmap_((Fl_Image*)img);
+ else if (d == 0) shape_bitmap_((Fl_Image*)img);
+ else if (d == 2 || d == 4) shape_alpha_((Fl_Image*)img, d - 1);
+ else if ((d == 1 || d == 3) && img->count() == 1) shape_alpha_((Fl_Image*)img, 0);
+}
+
+
+void Fl_X11_Window_Driver::combine_mask()
+{
+ typedef void (*XShapeCombineMask_type)(Display*, int, int, int, int, Pixmap, int);
+ static XShapeCombineMask_type XShapeCombineMask_f = NULL;
+ static int beenhere = 0;
+ typedef Bool (*XShapeQueryExtension_type)(Display*, int*, int*);
+ if (!beenhere) {
+ beenhere = 1;
+#if HAVE_DLSYM && HAVE_DLFCN_H
+ fl_open_display();
+ void *handle = dlopen(NULL, RTLD_LAZY); // search symbols in executable
+ XShapeQueryExtension_type XShapeQueryExtension_f = (XShapeQueryExtension_type)dlsym(handle, "XShapeQueryExtension");
+ XShapeCombineMask_f = (XShapeCombineMask_type)dlsym(handle, "XShapeCombineMask");
+ // make sure that the X server has the SHAPE extension
+ int error_base, shapeEventBase;
+ if ( !( XShapeQueryExtension_f && XShapeCombineMask_f &&
+ XShapeQueryExtension_f(fl_display, &shapeEventBase, &error_base) ) ) XShapeCombineMask_f = NULL;
+#endif
+ }
+ if (!XShapeCombineMask_f) return;
+ shape_data_->lw_ = pWindow->w();
+ shape_data_->lh_ = pWindow->h();
+ Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_);
+ Pixmap pbitmap = XCreateBitmapFromData(fl_display, fl_xid(pWindow),
+ (const char*)*temp->data(),
+ temp->w(), temp->h());
+ XShapeCombineMask_f(fl_display, fl_xid(pWindow), ShapeBounding, 0, 0, pbitmap, ShapeSet);
+ if (pbitmap != None) XFreePixmap(fl_display, pbitmap);
+ delete temp;
+}
+
+
+void Fl_X11_Window_Driver::draw() {
+ if (shape_data_) {
+ if (( shape_data_->lw_ != pWindow->w() || shape_data_->lh_ != pWindow->h() ) && shape_data_->shape_) {
+ // size of window has changed since last time
+ combine_mask();
+ }
+ }
+ Fl_Window_Driver::draw();
+}
+
//
// End of "$Id$".
//