diff options
Diffstat (limited to 'src/drivers/Android/Fl_Android_Window_Driver.cxx')
| -rw-r--r-- | src/drivers/Android/Fl_Android_Window_Driver.cxx | 732 |
1 files changed, 732 insertions, 0 deletions
diff --git a/src/drivers/Android/Fl_Android_Window_Driver.cxx b/src/drivers/Android/Fl_Android_Window_Driver.cxx new file mode 100644 index 000000000..7417f4af1 --- /dev/null +++ b/src/drivers/Android/Fl_Android_Window_Driver.cxx @@ -0,0 +1,732 @@ +// +// "$Id: Fl_Android_Window_Driver.cxx 12641 2018-01-31 21:17:17Z AlbrechtS $" +// +// Definition of Apple Cocoa window driver. +// +// Copyright 1998-2018 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" +#include <FL/fl_draw.H> +#include <FL/Fl.H> +#include <FL/Fl_Window.H> +#include <FL/Fl_Image.H> +#include <FL/Fl_Bitmap.H> +#include <FL/Fl_Window.H> +#include <FL/Fl_Overlay_Window.H> +#include <FL/platform.H> +#include "Fl_Android_Window_Driver.H" +#include "Fl_Android_Screen_Driver.H" +#include "Fl_Android_Graphics_Driver.H" + + +#if 0 + +#include <windows.h> +#include <math.h> // for ceil() + +#if USE_COLORMAP +extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx +#endif + +#endif + + +Fl_Window *Fl_Android_Window_Driver::sCurrent = 0L; + + +Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) +{ + return new Fl_Android_Window_Driver(w); +} + +void Fl_Window_Driver::default_icons(Fl_RGB_Image const**, int) { +} + +Window fl_window = 0; + + +void Fl_Android_Window_Driver::show() +{ + if (!shown()) { + // make window + fl_open_display(); + pWindow->set_visible(); + Fl_X *x = new Fl_X; + x->w = pWindow; + i(x); + x->next = Fl_X::first; + Fl_X::first = x; + } else { + // bring window to front + } +} + +#if 0 + +Fl_WinAPI_Window_Driver::Fl_WinAPI_Window_Driver(Fl_Window *win) +: Fl_Window_Driver(win) +{ + icon_ = new icon_data; + memset(icon_, 0, sizeof(icon_data)); + cursor = NULL; + screen_num_ = -1; +} + + +Fl_WinAPI_Window_Driver::~Fl_WinAPI_Window_Driver() +{ + if (shape_data_) { + delete shape_data_->todelete_; + delete shape_data_; + } + delete icon_; +} + +int Fl_WinAPI_Window_Driver::screen_num() { + if (pWindow->parent()) { + screen_num_ = pWindow->top_window()->driver()->screen_num(); + } + return screen_num_ >= 0 ? screen_num_ : 0; +} + +//FILE*LOG=fopen("log.log","w"); + +void Fl_WinAPI_Window_Driver::screen_num(int n) { +//fprintf(LOG, "screen_num setter old=%d new=%d\n",screen_num_, n);fflush(LOG); + screen_num_ = n; +} + + +RECT // frame of the decorated window in screen coordinates + Fl_WinAPI_Window_Driver::border_width_title_bar_height( + int &bx, // left and right border width + int &by, // bottom border height (=bx) + int &bt // height of window title bar + ) +{ + Fl_Window *win = pWindow; + RECT r = {0,0,0,0}; + bx = by = bt = 0; + if (win->shown() && !win->parent() && win->border() && win->visible()) { + static HMODULE dwmapi_dll = LoadLibrary("dwmapi.dll"); + typedef HRESULT (WINAPI* DwmGetWindowAttribute_type)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); + static DwmGetWindowAttribute_type DwmGetWindowAttribute = dwmapi_dll ? + (DwmGetWindowAttribute_type)GetProcAddress(dwmapi_dll, "DwmGetWindowAttribute") : NULL; + int need_r = 1; + if (DwmGetWindowAttribute) { + const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9; + if ( DwmGetWindowAttribute(fl_xid(win), DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK ) { + need_r = 0; + } + } + if (need_r) { + GetWindowRect(fl_xid(win), &r); + } + int width, height; +#ifdef FLTK_HIDPI_SUPPORT + RECT rc; + GetClientRect(fl_xid(win), &rc); + width = rc.right; + height = rc.bottom; +#else + float scaling = ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->DWM_scaling_factor(); + width = int(win->w() * scaling); + height = int(win->h() * scaling); +#endif + bx = (r.right - r.left - width)/2; + if (bx < 1) bx = 1; + by = bx; + bt = r.bottom - r.top - height - 2 * by; + } + return r; +} + + +// --- window data + +int Fl_WinAPI_Window_Driver::decorated_w() +{ + int bt, bx, by; + float s = Fl::screen_driver()->scale(screen_num()); + border_width_title_bar_height(bx, by, bt); + int mini_bx = bx/s; if (mini_bx < 1) mini_bx = 1; + return w() + 2 * mini_bx; +} + +int Fl_WinAPI_Window_Driver::decorated_h() +{ + int bt, bx, by; + border_width_title_bar_height(bx, by, bt); +#ifdef FLTK_HIDPI_SUPPORT + float s = Fl::screen_driver()->scale(screen_num()); + int mini_by = by/s; if (mini_by < 1) mini_by = 1; + return h() + (bt + by)/s + mini_by; +#else + float scaling = ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->DWM_scaling_factor(); + return h() + bt/scaling + 2 * by +1; +#endif +} + + +// --- window management + + + +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_begin() +{ + if (shape_data_) { + float s = Fl::screen_driver()->scale(screen_num()); + if ((shape_data_->lw_ != s*w() || shape_data_->lh_ != s*h()) && shape_data_->shape_) { + // size of window has changed since last time + shape_data_->lw_ = s*w(); + shape_data_->lh_ = s*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; + } + } +} + + +void Fl_WinAPI_Window_Driver::flush_double() +{ + if (!shown()) return; + pWindow->make_current(); // make sure fl_gc is non-zero + Fl_X *i = Fl_X::i(pWindow); + if (!i) return; // window not yet created + + if (!other_xid) { + other_xid = fl_create_offscreen(w(), h()); + pWindow->clear_damage(FL_DAMAGE_ALL); + } + if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { + fl_clip_region(i->region); i->region = 0; + fl_begin_offscreen(other_xid); + fl_graphics_driver->clip_region( 0 ); + draw(); + fl_end_offscreen(); + } + + int X,Y,W,H; fl_clip_box(0,0,w(),h(),X,Y,W,H); + if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid, X, Y); +} + + +void Fl_WinAPI_Window_Driver::flush_overlay() +{ + Fl_Overlay_Window *oWindow = pWindow->as_overlay_window(); + + if (!shown()) return; + pWindow->make_current(); // make sure fl_gc is non-zero + Fl_X *i = Fl_X::i(pWindow); + if (!i) return; // window not yet created + + int eraseoverlay = (pWindow->damage()&FL_DAMAGE_OVERLAY); + pWindow->clear_damage((uchar)(pWindow->damage()&~FL_DAMAGE_OVERLAY)); + + if (!other_xid) { + other_xid = fl_create_offscreen(w(), h()); + pWindow->clear_damage(FL_DAMAGE_ALL); + } + if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { + fl_clip_region(i->region); i->region = 0; + fl_begin_offscreen(other_xid); + fl_graphics_driver->clip_region(0); + draw(); + fl_end_offscreen(); + } + + if (eraseoverlay) fl_clip_region(0); + int X, Y, W, H; fl_clip_box(0, 0, w(), h(), X, Y, W, H); + if (other_xid) fl_copy_offscreen(X, Y, W, H, other_xid, X, Y); + + if (overlay() == oWindow) oWindow->draw_overlay(); +} + + +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)) + 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::make_current() { + fl_GetDC(fl_xid(pWindow)); + +#if USE_COLORMAP + // Windows maintains a hardware and software color palette; the + // SelectPalette() call updates the current soft->hard mapping + // for all drawing calls, so we must select it here before any + // code does any drawing... + fl_select_palette(); +#endif // USE_COLORMAP + + fl_graphics_driver->clip_region(0); + ((Fl_GDI_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num())); +} + +void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) { + if (shown() && !parent()) { + if (!name) name = ""; + size_t l = strlen(name); + // WCHAR *lab = (WCHAR*) malloc((l + 1) * sizeof(short)); + // l = fl_utf2unicode((unsigned char*)name, l, (wchar_t*)lab); + unsigned wlen = fl_utf8toUtf16(name, (unsigned) l, NULL, 0); // Pass NULL to query length + wlen++; + unsigned short * lab = (unsigned short*)malloc(sizeof(unsigned short)*wlen); + wlen = fl_utf8toUtf16(name, (unsigned) l, lab, wlen); + lab[wlen] = 0; + SetWindowTextW(fl_xid(pWindow), (WCHAR *)lab); + free(lab); + } +} + + +extern void fl_clipboard_notify_retarget(HWND wnd); +extern void fl_update_clipboard(void); + +void Fl_WinAPI_Window_Driver::hide() { + Fl_X* ip = Fl_X::i(pWindow); + // STR#3079: if there remains a window and a non-modal window, and the window is deleted, + // the app remains running without any apparent window. + // Bug mechanism: hiding an owner window unmaps the owned (non-modal) window(s) + // but does not delete it(them) in FLTK. + // Fix for it: + // when hiding a window, build list of windows it owns, and do hide/show on them. + int count = 0; + Fl_Window *win, **doit = NULL; + for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { + if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == ip->xid) { + count++; + } + } + if (count) { + doit = new Fl_Window*[count]; + count = 0; + for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) { + if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == ip->xid) { + doit[count++] = win; + } + } + } + + if (hide_common()) return; + + // make sure any custom icons get freed +// icons(NULL, 0); // free_icons() is called by the Fl_Window destructor + // this little trick keeps the current clipboard alive, even if we are about + // to destroy the window that owns the selection. + if (GetClipboardOwner()==ip->xid) + fl_update_clipboard(); + // Make sure we unlink this window from the clipboard chain + fl_clipboard_notify_retarget(ip->xid); + // Send a message to myself so that I'll get out of the event loop... + PostMessage(ip->xid, WM_APP, 0, 0); + if (private_dc) fl_release_dc(ip->xid, private_dc); + if (ip->xid == fl_window && fl_graphics_driver->gc()) { + fl_release_dc(fl_window, (HDC)fl_graphics_driver->gc()); + fl_window = (HWND)-1; + fl_graphics_driver->gc(0); +# ifdef FLTK_USE_CAIRO + if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); +# endif + } + + if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); + + // this little trickery seems to avoid the popup window stacking problem + HWND p = GetForegroundWindow(); + if (p==GetParent(ip->xid)) { + ShowWindow(ip->xid, SW_HIDE); + ShowWindow(p, SW_SHOWNA); + } + DestroyWindow(ip->xid); + // end of fix for STR#3079 + if (count) { + int ii; + for (ii = 0; ii < count; ii++) doit[ii]->hide(); + for (ii = 0; ii < count; ii++) { + if (ii != 0) doit[0]->show(); // Fix for STR#3165 + doit[ii]->show(); + } + delete[] doit; + } + // Try to stop the annoying "raise another program" behavior + if (pWindow->non_modal() && Fl::first_window() && Fl::first_window()->shown()) + Fl::first_window()->show(); + delete ip; + screen_num_ = -1; +} + + +void Fl_WinAPI_Window_Driver::map() { + ShowWindow(fl_xid(pWindow), SW_RESTORE); // extra map calls are harmless +} + + +void Fl_WinAPI_Window_Driver::unmap() { + ShowWindow(fl_xid(pWindow), SW_HIDE); +} + +#if !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning + +void Fl_WinAPI_Window_Driver::make_fullscreen(int X, int Y, int W, int H) { + Fl_Window *w = pWindow; + int top, bottom, left, right; + int sx, sy, sw, sh; + + top = fullscreen_screen_top(); + bottom = fullscreen_screen_bottom(); + left = fullscreen_screen_left(); + right = fullscreen_screen_right(); + + if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { + top = screen_num(); + bottom = top; + left = top; + right = top; + } + + Fl::screen_xywh(sx, sy, sw, sh, top); + Y = sy; + Fl::screen_xywh(sx, sy, sw, sh, bottom); + H = sy + sh - Y; + Fl::screen_xywh(sx, sy, sw, sh, left); + X = sx; + Fl::screen_xywh(sx, sy, sw, sh, right); + W = sx + sw - X; + + DWORD flags = GetWindowLong(fl_xid(w), GWL_STYLE); + flags = flags & ~(WS_THICKFRAME|WS_CAPTION); + SetWindowLong(fl_xid(w), GWL_STYLE, flags); + + // SWP_NOSENDCHANGING is so that we can override size limits + float s = Fl::screen_driver()->scale(screen_num()); + SetWindowPos(fl_xid(w), HWND_TOP, X*s, Y*s, W*s, H*s, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); +} + +#endif // !defined(FL_DOXYGEN) // FIXME - silence Doxygen warning + + +void Fl_WinAPI_Window_Driver::fullscreen_on() { + pWindow->_set_fullscreen(); + make_fullscreen(x(), y(), w(), h()); + Fl::handle(FL_FULLSCREEN, pWindow); +} + + +void Fl_WinAPI_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { + pWindow->_clear_fullscreen(); + DWORD style = GetWindowLong(fl_xid(pWindow), GWL_STYLE); + // Remove the xid temporarily so that Fl_WinAPI_Window_Driver::fake_X_wm() behaves like it + // does in Fl_WinAPI_Window_Driver::makeWindow(). + HWND xid = fl_xid(pWindow); + Fl_X::i(pWindow)->xid = NULL; + int wx, wy, bt, bx, by; + switch (fake_X_wm(wx, wy, bt, bx, by)) { + case 0: + break; + case 1: + style |= WS_CAPTION; + break; + case 2: + if (border()) { + style |= WS_THICKFRAME | WS_CAPTION; + } + break; + } + Fl_X::i(pWindow)->xid = xid; + // compute window position and size in scaled units + float s = Fl::screen_driver()->scale(screen_num()); + int scaledX = ceil(X*s), scaledY= ceil(Y*s), scaledW = ceil(W*s), scaledH = ceil(H*s); + // Adjust for decorations (but not if that puts the decorations + // outside the screen) + if ((X != x()) || (Y != y())) { + scaledX -= bx; + scaledY -= by+bt; + } + scaledW += bx*2; + scaledH += by*2+bt; + SetWindowLong(fl_xid(pWindow), GWL_STYLE, style); + SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); + Fl::handle(FL_FULLSCREEN, pWindow); +} + + +void Fl_WinAPI_Window_Driver::iconize() { + ShowWindow(fl_xid(pWindow), SW_SHOWMINNOACTIVE); +} + + +void Fl_WinAPI_Window_Driver::decoration_sizes(int *top, int *left, int *right, int *bottom) { + if (size_range_set() && (maxw() != minw() || maxh() != minh())) { + *left = *right = GetSystemMetrics(SM_CXSIZEFRAME); + *top = *bottom = GetSystemMetrics(SM_CYSIZEFRAME); + } else { + *left = *right = GetSystemMetrics(SM_CXFIXEDFRAME); + *top = *bottom = GetSystemMetrics(SM_CYFIXEDFRAME); + } + *top += GetSystemMetrics(SM_CYCAPTION); +} + +int Fl_WinAPI_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, + void (*draw_area)(void*, int,int,int,int), void* data) +{ + typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT); + static fl_GetRandomRgn_func fl_GetRandomRgn = 0L; + static char first_time = 1; + // We will have to do some Region magic now, so let's see if the + // required function is available (and it should be starting w/Win95) + if (first_time) { + HMODULE hMod = GetModuleHandle("GDI32.DLL"); + if (hMod) { + fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn"); + } + first_time = 0; + } + float s = Fl::screen_driver()->scale(screen_num()); + src_x *= s; src_y *= s; src_w *= s; src_h *= s; dest_x *= s; dest_y *= s; + // Now check if the source scrolling area is fully visible. + // If it is, we will do a quick scroll and just update the + // newly exposed area. If it is not, we go the safe route and + // re-render the full area instead. + // Note 1: we could go and find the areas that are actually + // obscured and recursively call fl_scroll for the newly found + // rectangles. However, this practice would rely on the + // elements of the undocumented Rgn structure. + // Note 2: although this method should take care of most + // multi-screen solutions, it will not solve issues scrolling + // from a different resolution screen onto another. + // Note 3: this has been tested with image maps, too. + HDC gc = (HDC)fl_graphics_driver->gc(); + if (fl_GetRandomRgn) { + // get the DC region minus all overlapping windows + HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0); + fl_GetRandomRgn(gc, sys_rgn, 4); + // now get the source scrolling rectangle + HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h); + POINT offset = { 0, 0 }; + if (GetDCOrgEx(gc, &offset)) { + OffsetRgn(src_rgn, offset.x, offset.y); + } + // see if all source pixels are available in the system region + // Note: we could be a bit more merciful and subtract the + // scroll destination region as well. + HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0); + int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF); + DeleteObject(dst_rgn); + DeleteObject(src_rgn); + DeleteObject(sys_rgn); + if (r != NULLREGION) { + return 1; + } + } + // Great, we can do an accelerated scroll instead of re-rendering + BitBlt(gc, dest_x, dest_y, src_w, src_h, gc, src_x, src_y,SRCCOPY); + return 0; +} + +Fl_WinAPI_Window_Driver::type_for_resize_window_between_screens Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_ = {0, false}; + +void Fl_WinAPI_Window_Driver::resize_after_screen_change(void *data) { + Fl_Window *win = (Fl_Window*)data; + RECT r; + GetClientRect(fl_xid(win), &r); + float old_f = float(r.right)/win->w(); + int ns = data_for_resize_window_between_screens_.screen; + win->driver()->resize_after_scale_change(ns, old_f, Fl::screen_driver()->scale(ns)); + data_for_resize_window_between_screens_.busy = false; +} + +#endif + +// +// End of "$Id: Fl_Android_Window_Driver.cxx 12641 2018-01-31 21:17:17Z AlbrechtS $". +// |
