2016-02-19 21:41:02 +00:00
|
|
|
//
|
|
|
|
|
// "$Id$"
|
|
|
|
|
//
|
|
|
|
|
// Definition of Apple Cocoa window driver.
|
|
|
|
|
//
|
|
|
|
|
// Copyright 1998-2016 by Bill Spitzak and others.
|
|
|
|
|
//
|
|
|
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
|
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
|
//
|
|
|
|
|
// http://www.fltk.org/COPYING.php
|
|
|
|
|
//
|
|
|
|
|
// Please report all bugs and problems on the following page:
|
|
|
|
|
//
|
|
|
|
|
// http://www.fltk.org/str.php
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "../../config_lib.h"
|
2016-03-11 08:31:36 +00:00
|
|
|
#include <FL/Fl.H>
|
2016-02-26 16:12:43 +00:00
|
|
|
#include "Fl_WinAPI_Window_Driver.H"
|
2016-03-10 17:19:34 +00:00
|
|
|
#include <windows.h>
|
2016-02-19 21:41:02 +00:00
|
|
|
|
2016-02-19 22:21:02 +00:00
|
|
|
Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w)
|
|
|
|
|
{
|
|
|
|
|
return new Fl_WinAPI_Window_Driver(w);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fl_WinAPI_Window_Driver::Fl_WinAPI_Window_Driver(Fl_Window *win)
|
|
|
|
|
: Fl_Window_Driver(win)
|
|
|
|
|
{
|
2016-03-10 22:26:40 +00:00
|
|
|
icon_ = new Fl_Window_Driver::icon_data;
|
|
|
|
|
memset(icon_, 0, sizeof(Fl_Window_Driver::icon_data));
|
2016-02-19 22:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 18:45:50 +00:00
|
|
|
Fl_WinAPI_Window_Driver::~Fl_WinAPI_Window_Driver()
|
|
|
|
|
{
|
|
|
|
|
if (shape_data_) {
|
|
|
|
|
delete shape_data_->todelete_;
|
|
|
|
|
delete shape_data_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-10 17:19:34 +00:00
|
|
|
void Fl_WinAPI_Window_Driver::shape_bitmap_(Fl_Image* b) {
|
|
|
|
|
shape_data_->shape_ = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Fl_WinAPI_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_WinAPI_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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline BYTE bit(int x) { return (BYTE)(1 << (x%8)); }
|
|
|
|
|
|
|
|
|
|
static HRGN bitmap2region(Fl_Image* image) {
|
|
|
|
|
HRGN hRgn = 0;
|
|
|
|
|
/* Does this need to be dynamically determined, perhaps? */
|
|
|
|
|
const int ALLOC_UNIT = 100;
|
|
|
|
|
DWORD maxRects = ALLOC_UNIT;
|
|
|
|
|
|
|
|
|
|
RGNDATA* pData = (RGNDATA*)malloc(sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRects));
|
|
|
|
|
pData->rdh.dwSize = sizeof(RGNDATAHEADER);
|
|
|
|
|
pData->rdh.iType = RDH_RECTANGLES;
|
|
|
|
|
pData->rdh.nCount = pData->rdh.nRgnSize = 0;
|
|
|
|
|
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
|
|
|
|
|
|
|
|
|
|
const int bytesPerLine = (image->w() + 7)/8;
|
|
|
|
|
BYTE* p, *data = (BYTE*)*image->data();
|
|
|
|
|
for (int y = 0; y < image->h(); y++) {
|
|
|
|
|
// each row, left to right
|
|
|
|
|
for (int x = 0; x < image->w(); x++) {
|
|
|
|
|
int x0 = x;
|
|
|
|
|
while (x < image->w()) {
|
|
|
|
|
p = data + x / 8;
|
|
|
|
|
if (!((*p) & bit(x))) break; // transparent pixel
|
|
|
|
|
x++;
|
|
|
|
|
}
|
|
|
|
|
if (x > x0) {
|
|
|
|
|
RECT *pr;
|
|
|
|
|
/* Add the pixels (x0, y) to (x, y+1) as a new rectangle
|
|
|
|
|
* in the region
|
|
|
|
|
*/
|
|
|
|
|
if (pData->rdh.nCount >= maxRects) {
|
|
|
|
|
maxRects += ALLOC_UNIT;
|
|
|
|
|
pData = (RGNDATA*)realloc(pData, sizeof(RGNDATAHEADER)
|
|
|
|
|
+ (sizeof(RECT)*maxRects));
|
|
|
|
|
}
|
|
|
|
|
pr = (RECT*)&pData->Buffer;
|
|
|
|
|
SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
|
|
|
|
|
if (x0 < pData->rdh.rcBound.left)
|
|
|
|
|
pData->rdh.rcBound.left = x0;
|
|
|
|
|
if (y < pData->rdh.rcBound.top)
|
|
|
|
|
pData->rdh.rcBound.top = y;
|
|
|
|
|
if (x > pData->rdh.rcBound.right)
|
|
|
|
|
pData->rdh.rcBound.right = x;
|
|
|
|
|
if (y+1 > pData->rdh.rcBound.bottom)
|
|
|
|
|
pData->rdh.rcBound.bottom = y+1;
|
|
|
|
|
pData->rdh.nCount++;
|
|
|
|
|
/* On Windows98, ExtCreateRegion() may fail if the
|
|
|
|
|
* number of rectangles is too large (ie: >
|
|
|
|
|
* 4000). Therefore, we have to create the region by
|
|
|
|
|
* multiple steps.
|
|
|
|
|
*/
|
|
|
|
|
if (pData->rdh.nCount == 2000) {
|
|
|
|
|
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER)
|
|
|
|
|
+ (sizeof(RECT)*maxRects), pData);
|
|
|
|
|
if (hRgn) {
|
|
|
|
|
CombineRgn(hRgn, hRgn, h, RGN_OR);
|
|
|
|
|
DeleteObject(h);
|
|
|
|
|
} else
|
|
|
|
|
hRgn = h;
|
|
|
|
|
pData->rdh.nCount = 0;
|
|
|
|
|
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Go to next row */
|
|
|
|
|
data += bytesPerLine;
|
|
|
|
|
}
|
|
|
|
|
/* Create or extend the region with the remaining rectangles*/
|
|
|
|
|
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER)
|
|
|
|
|
+ (sizeof(RECT)*maxRects), pData);
|
|
|
|
|
if (hRgn) {
|
|
|
|
|
CombineRgn(hRgn, hRgn, h, RGN_OR);
|
|
|
|
|
DeleteObject(h);
|
|
|
|
|
} else hRgn = h;
|
|
|
|
|
free(pData); // I've created the region so I can free this now, right?
|
|
|
|
|
return hRgn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Fl_WinAPI_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
|
|
|
|
|
shape_data_->lw_ = pWindow->w();
|
|
|
|
|
shape_data_->lh_ = pWindow->h();
|
|
|
|
|
Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_);
|
|
|
|
|
HRGN region = bitmap2region(temp);
|
|
|
|
|
SetWindowRgn(fl_xid(pWindow), region, TRUE); // the system deletes the region when it's no longer needed
|
|
|
|
|
delete temp;
|
|
|
|
|
}
|
|
|
|
|
} Fl_Window_Driver::draw();
|
|
|
|
|
}
|
2016-02-19 22:21:02 +00:00
|
|
|
|
2016-03-10 22:26:40 +00:00
|
|
|
void Fl_WinAPI_Window_Driver::icons(const Fl_RGB_Image *icons[], int count) {
|
|
|
|
|
free_icons();
|
|
|
|
|
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
icon_->icons = new Fl_RGB_Image*[count];
|
|
|
|
|
icon_->count = count;
|
|
|
|
|
// FIXME: Fl_RGB_Image lacks const modifiers on methods
|
|
|
|
|
for (int i = 0;i < count;i++)
|
|
|
|
|
icon_->icons[i] = (Fl_RGB_Image*)((Fl_RGB_Image*)icons[i])->copy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Fl_X::i(pWindow))
|
|
|
|
|
Fl_X::i(pWindow)->set_icons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const void *Fl_WinAPI_Window_Driver::icon() const {
|
|
|
|
|
return icon_->legacy_icon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Fl_WinAPI_Window_Driver::icon(const void * ic) {
|
|
|
|
|
free_icons();
|
|
|
|
|
icon_->legacy_icon = ic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Fl_WinAPI_Window_Driver::free_icons() {
|
|
|
|
|
int i;
|
|
|
|
|
icon_->legacy_icon = 0L;
|
|
|
|
|
if (icon_->icons) {
|
|
|
|
|
for (i = 0;i < icon_->count;i++)
|
|
|
|
|
delete icon_->icons[i];
|
|
|
|
|
delete [] icon_->icons;
|
|
|
|
|
icon_->icons = 0L;
|
|
|
|
|
}
|
|
|
|
|
icon_->count = 0;
|
|
|
|
|
if (icon_->big_icon)
|
|
|
|
|
DestroyIcon(icon_->big_icon);
|
|
|
|
|
if (icon_->small_icon)
|
|
|
|
|
DestroyIcon(icon_->small_icon);
|
|
|
|
|
icon_->big_icon = NULL;
|
|
|
|
|
icon_->small_icon = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Fl_WinAPI_Window_Driver::icons(HICON big_icon, HICON small_icon)
|
|
|
|
|
{
|
|
|
|
|
free_icons();
|
|
|
|
|
|
|
|
|
|
if (big_icon != NULL)
|
|
|
|
|
icon_->big_icon = CopyIcon(big_icon);
|
|
|
|
|
if (small_icon != NULL)
|
|
|
|
|
icon_->small_icon = CopyIcon(small_icon);
|
|
|
|
|
|
|
|
|
|
if (Fl_X::i(pWindow))
|
|
|
|
|
Fl_X::i(pWindow)->set_icons();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 08:31:36 +00:00
|
|
|
void Fl_WinAPI_Window_Driver::wait_for_expose() {
|
|
|
|
|
if (!pWindow->shown()) return;
|
|
|
|
|
Fl_X *i = Fl_X::i(pWindow);
|
|
|
|
|
while (!i || i->wait_for_expose) {
|
|
|
|
|
Fl::wait();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 21:41:02 +00:00
|
|
|
//
|
|
|
|
|
// End of "$Id$".
|
|
|
|
|
//
|