|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Double_Window.cxx 8198 2011-01-06 10:24:58Z manolo $" 00003 // 00004 // Double-buffered window code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <config.h> 00029 #include <FL/Fl.H> 00030 #include <FL/Fl_Double_Window.H> 00031 #include <FL/Fl_Printer.H> 00032 #include <FL/x.H> 00033 #include <FL/fl_draw.H> 00034 00035 // On systems that support double buffering "naturally" the base 00036 // Fl_Window class will probably do double-buffer and this subclass 00037 // does nothing. 00038 00039 #if USE_XDBE 00040 00041 #include <X11/extensions/Xdbe.h> 00042 00043 static int use_xdbe; 00044 00045 static int can_xdbe() { 00046 static int tried; 00047 if (!tried) { 00048 tried = 1; 00049 int event_base, error_base; 00050 if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; 00051 Drawable root = RootWindow(fl_display,fl_screen); 00052 int numscreens = 1; 00053 XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens); 00054 if (!a) return 0; 00055 for (int j = 0; j < a->count; j++) 00056 if (a->visinfo[j].visual == fl_visual->visualid 00057 /*&& a->visinfo[j].perflevel > 0*/) {use_xdbe = 1; break;} 00058 XdbeFreeVisualInfo(a); 00059 } 00060 return use_xdbe; 00061 } 00062 #endif 00063 00064 void Fl_Double_Window::show() { 00065 Fl_Window::show(); 00066 } 00067 00068 static void fl_copy_offscreen_to_display(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); 00069 00079 void fl_copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { 00080 if( fl_graphics_driver == fl_display_device->driver()) { 00081 fl_copy_offscreen_to_display(x, y, w, h, pixmap, srcx, srcy); 00082 } 00083 else { // when copy is not to the display 00084 fl_begin_offscreen(pixmap); 00085 uchar *img = fl_read_image(NULL, srcx, srcy, w, h, 0); 00086 fl_end_offscreen(); 00087 fl_draw_image(img, x, y, w, h, 3, 0); 00088 delete img; 00089 } 00090 } 00093 #if defined(USE_X11) 00094 00095 static void fl_copy_offscreen_to_display(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { 00096 XCopyArea(fl_display, pixmap, fl_window, fl_gc, srcx, srcy, w, h, x, y); 00097 } 00098 00099 00100 // maybe someone feels inclined to implement alpha blending on X11? 00101 char fl_can_do_alpha_blending() { 00102 return 0; 00103 } 00104 #elif defined(WIN32) 00105 00106 // Code used to switch output to an off-screen window. See macros in 00107 // win32.H which save the old state in local variables. 00108 00109 typedef struct { BYTE a; BYTE b; BYTE c; BYTE d; } FL_BLENDFUNCTION; 00110 typedef BOOL (WINAPI* fl_alpha_blend_func) 00111 (HDC,int,int,int,int,HDC,int,int,int,int,FL_BLENDFUNCTION); 00112 static fl_alpha_blend_func fl_alpha_blend = NULL; 00113 static FL_BLENDFUNCTION blendfunc = { 0, 0, 255, 1}; 00114 00115 /* 00116 * This function checks if the version of MSWindows that we 00117 * curently run on supports alpha blending for bitmap transfers 00118 * and finds the required function if so. 00119 */ 00120 char fl_can_do_alpha_blending() { 00121 static char been_here = 0; 00122 static char can_do = 0; 00123 // do this test only once 00124 if (been_here) return can_do; 00125 been_here = 1; 00126 // load the library that implements alpha blending 00127 HMODULE hMod = LoadLibrary("MSIMG32.DLL"); 00128 // give up if that doesn't exist (Win95?) 00129 if (!hMod) return 0; 00130 // now find the blending function inside that dll 00131 fl_alpha_blend = (fl_alpha_blend_func)GetProcAddress(hMod, "AlphaBlend"); 00132 // give up if we can't find it (Win95) 00133 if (!fl_alpha_blend) return 0; 00134 // we have the call, but does our display support alpha blending? 00135 // get the desktop's device context 00136 HDC dc = GetDC(0L); 00137 if (!dc) return 0; 00138 // check the device capabilities flags. However GetDeviceCaps 00139 // does not return anything useful, so we have to do it manually: 00140 00141 HBITMAP bm = CreateCompatibleBitmap(dc, 1, 1); 00142 HDC new_gc = CreateCompatibleDC(dc); 00143 int save = SaveDC(new_gc); 00144 SelectObject(new_gc, bm); 00145 /*COLORREF set = */ SetPixel(new_gc, 0, 0, 0x01010101); 00146 BOOL alpha_ok = fl_alpha_blend(dc, 0, 0, 1, 1, new_gc, 0, 0, 1, 1, blendfunc); 00147 RestoreDC(new_gc, save); 00148 DeleteDC(new_gc); 00149 DeleteObject(bm); 00150 ReleaseDC(0L, dc); 00151 00152 if (alpha_ok) can_do = 1; 00153 return can_do; 00154 } 00155 00156 HDC fl_makeDC(HBITMAP bitmap) { 00157 HDC new_gc = CreateCompatibleDC(fl_gc); 00158 SetTextAlign(new_gc, TA_BASELINE|TA_LEFT); 00159 SetBkMode(new_gc, TRANSPARENT); 00160 #if USE_COLORMAP 00161 if (fl_palette) SelectPalette(new_gc, fl_palette, FALSE); 00162 #endif 00163 SelectObject(new_gc, bitmap); 00164 return new_gc; 00165 } 00166 00167 static void fl_copy_offscreen_to_display(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { 00168 HDC new_gc = CreateCompatibleDC(fl_gc); 00169 int save = SaveDC(new_gc); 00170 SelectObject(new_gc, bitmap); 00171 BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); 00172 RestoreDC(new_gc, save); 00173 DeleteDC(new_gc); 00174 } 00175 00176 void fl_copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { 00177 HDC new_gc = CreateCompatibleDC(fl_gc); 00178 int save = SaveDC(new_gc); 00179 SelectObject(new_gc, bitmap); 00180 BOOL alpha_ok = 0; 00181 // first try to alpha blend 00182 // if to printer, always try alpha_blend 00183 int to_display = Fl_Surface_Device::surface()->class_name() == Fl_Display_Device::class_id; // true iff display output 00184 if ( (to_display && fl_can_do_alpha_blending()) || Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { 00185 alpha_ok = fl_alpha_blend(fl_gc, x, y, w, h, new_gc, srcx, srcy, w, h, blendfunc); 00186 } 00187 // if that failed (it shouldn't), still copy the bitmap over, but now alpha is 1 00188 if (!alpha_ok) { 00189 BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); 00190 } 00191 RestoreDC(new_gc, save); 00192 DeleteDC(new_gc); 00193 } 00194 00195 extern void fl_restore_clip(); 00196 00197 #elif defined(__APPLE_QUARTZ__) || defined(FL_DOXYGEN) 00198 00199 char fl_can_do_alpha_blending() { 00200 return 1; 00201 } 00202 00203 Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h) { 00204 void *data = calloc(w*h,4); 00205 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); 00206 CGContextRef ctx = CGBitmapContextCreate( 00207 data, w, h, 8, w*4, lut, kCGImageAlphaPremultipliedLast); 00208 CGColorSpaceRelease(lut); 00209 return (Fl_Offscreen)ctx; 00210 } 00211 00221 Fl_Offscreen fl_create_offscreen(int w, int h) { 00222 void *data = calloc(w*h,4); 00223 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); 00224 CGContextRef ctx = CGBitmapContextCreate( 00225 data, w, h, 8, w*4, lut, kCGImageAlphaNoneSkipLast); 00226 CGColorSpaceRelease(lut); 00227 return (Fl_Offscreen)ctx; 00228 } 00229 00230 static void bmProviderRelease (void *src, const void *data, size_t size) 00231 { 00232 CFIndex count = CFGetRetainCount(src); 00233 CFRelease(src); 00234 if(count == 1) free((void*)data); 00235 } 00236 00237 static void fl_copy_offscreen_to_display(int x,int y,int w,int h,Fl_Offscreen osrc,int srcx,int srcy) { 00238 CGContextRef src = (CGContextRef)osrc; 00239 void *data = CGBitmapContextGetData(src); 00240 int sw = CGBitmapContextGetWidth(src); 00241 int sh = CGBitmapContextGetHeight(src); 00242 CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(src); 00243 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); 00244 // when output goes to a Quartz printercontext, release of the bitmap must be 00245 // delayed after the end of the print page 00246 CFRetain(src); 00247 CGDataProviderRef src_bytes = CGDataProviderCreateWithData( src, data, sw*sh*4, bmProviderRelease); 00248 CGImageRef img = CGImageCreate( sw, sh, 8, 4*8, 4*sw, lut, alpha, 00249 src_bytes, 0L, false, kCGRenderingIntentDefault); 00250 // fl_push_clip(); 00251 CGRect rect = { { x, y }, { w, h } }; 00252 Fl_X::q_begin_image(rect, srcx, srcy, sw, sh); 00253 CGContextDrawImage(fl_gc, rect, img); 00254 Fl_X::q_end_image(); 00255 CGImageRelease(img); 00256 CGColorSpaceRelease(lut); 00257 CGDataProviderRelease(src_bytes); 00258 } 00259 00263 void fl_delete_offscreen(Fl_Offscreen ctx) { 00264 if (!ctx) return; 00265 void *data = CGBitmapContextGetData((CGContextRef)ctx); 00266 CFIndex count = CFGetRetainCount(ctx); 00267 CGContextRelease((CGContextRef)ctx); 00268 if(count == 1) free(data); 00269 } 00270 00271 const int stack_max = 16; 00272 static int stack_ix = 0; 00273 static CGContextRef stack_gc[stack_max]; 00274 static Window stack_window[stack_max]; 00275 static Fl_Surface_Device *_ss; 00276 00280 void fl_begin_offscreen(Fl_Offscreen ctx) { 00281 _ss = fl_surface; 00282 fl_display_device->set_current(); 00283 if (stack_ix<stack_max) { 00284 stack_gc[stack_ix] = fl_gc; 00285 stack_window[stack_ix] = fl_window; 00286 } else 00287 fprintf(stderr, "FLTK CGContext Stack overflow error\n"); 00288 stack_ix++; 00289 00290 fl_gc = (CGContextRef)ctx; 00291 fl_window = 0; 00292 CGContextSaveGState(fl_gc); 00293 fl_push_no_clip(); 00294 } 00295 00298 void fl_end_offscreen() { 00299 Fl_X::q_release_context(); 00300 fl_pop_clip(); 00301 if (stack_ix>0) 00302 stack_ix--; 00303 else 00304 fprintf(stderr, "FLTK CGContext Stack underflow error\n"); 00305 if (stack_ix<stack_max) { 00306 fl_gc = stack_gc[stack_ix]; 00307 fl_window = stack_window[stack_ix]; 00308 } 00309 _ss->set_current(); 00310 } 00311 00314 extern void fl_restore_clip(); 00315 00316 #else 00317 # error unsupported platform 00318 #endif 00319 00323 void Fl_Double_Window::flush() {flush(0);} 00324 00333 void Fl_Double_Window::flush(int eraseoverlay) { 00334 make_current(); // make sure fl_gc is non-zero 00335 Fl_X *myi = Fl_X::i(this); 00336 if (!myi->other_xid) { 00337 #if USE_XDBE 00338 if (can_xdbe()) { 00339 myi->other_xid = 00340 XdbeAllocateBackBufferName(fl_display, fl_xid(this), XdbeCopied); 00341 myi->backbuffer_bad = 1; 00342 } else 00343 #endif 00344 #if defined(USE_X11) || defined(WIN32) 00345 myi->other_xid = fl_create_offscreen(w(), h()); 00346 clear_damage(FL_DAMAGE_ALL); 00347 #elif defined(__APPLE_QUARTZ__) 00348 if (force_doublebuffering_) { 00349 myi->other_xid = fl_create_offscreen(w(), h()); 00350 clear_damage(FL_DAMAGE_ALL); 00351 } 00352 #else 00353 # error unsupported platform 00354 #endif 00355 } 00356 #if USE_XDBE 00357 if (use_xdbe) { 00358 if (myi->backbuffer_bad || eraseoverlay) { 00359 // Make sure we do a complete redraw... 00360 if (myi->region) {XDestroyRegion(myi->region); myi->region = 0;} 00361 clear_damage(FL_DAMAGE_ALL); 00362 myi->backbuffer_bad = 0; 00363 } 00364 00365 // Redraw as needed... 00366 if (damage()) { 00367 fl_clip_region(myi->region); myi->region = 0; 00368 fl_window = myi->other_xid; 00369 draw(); 00370 fl_window = myi->xid; 00371 } 00372 00373 // Copy contents of back buffer to window... 00374 XdbeSwapInfo s; 00375 s.swap_window = fl_xid(this); 00376 s.swap_action = XdbeCopied; 00377 XdbeSwapBuffers(fl_display, &s, 1); 00378 return; 00379 } else 00380 #endif 00381 if (damage() & ~FL_DAMAGE_EXPOSE) { 00382 fl_clip_region(myi->region); myi->region = 0; 00383 #ifdef WIN32 00384 HDC _sgc = fl_gc; 00385 fl_gc = fl_makeDC(myi->other_xid); 00386 int save = SaveDC(fl_gc); 00387 fl_restore_clip(); // duplicate region into new gc 00388 draw(); 00389 RestoreDC(fl_gc, save); 00390 DeleteDC(fl_gc); 00391 fl_gc = _sgc; 00392 //# if defined(FLTK_USE_CAIRO) 00393 //if Fl::cairo_autolink_context() Fl::cairo_make_current(this); // capture gc changes automatically to update the cairo context adequately 00394 //# endif 00395 #elif defined(__APPLE__) 00396 if ( myi->other_xid ) { 00397 fl_begin_offscreen( myi->other_xid ); 00398 fl_clip_region( 0 ); 00399 draw(); 00400 fl_end_offscreen(); 00401 } else { 00402 draw(); 00403 } 00404 #else // X: 00405 fl_window = myi->other_xid; 00406 draw(); 00407 fl_window = myi->xid; 00408 #endif 00409 } 00410 if (eraseoverlay) fl_clip_region(0); 00411 // on Irix (at least) it is faster to reduce the area copied to 00412 // the current clip region: 00413 int X,Y,W,H; fl_clip_box(0,0,w(),h(),X,Y,W,H); 00414 if (myi->other_xid) fl_copy_offscreen(X, Y, W, H, myi->other_xid, X, Y); 00415 } 00416 00417 void Fl_Double_Window::resize(int X,int Y,int W,int H) { 00418 int ow = w(); 00419 int oh = h(); 00420 Fl_Window::resize(X,Y,W,H); 00421 #if USE_XDBE 00422 if (use_xdbe) { 00423 Fl_X* myi = Fl_X::i(this); 00424 if (myi && myi->other_xid && (ow < w() || oh < h())) { 00425 // STR #2152: Deallocate the back buffer to force creation of a new one. 00426 XdbeDeallocateBackBufferName(fl_display,myi->other_xid); 00427 myi->other_xid = 0; 00428 } 00429 return; 00430 } 00431 #endif 00432 Fl_X* myi = Fl_X::i(this); 00433 if (myi && myi->other_xid && (ow != w() || oh != h())) { 00434 fl_delete_offscreen(myi->other_xid); 00435 myi->other_xid = 0; 00436 } 00437 } 00438 00439 void Fl_Double_Window::hide() { 00440 Fl_X* myi = Fl_X::i(this); 00441 if (myi && myi->other_xid) { 00442 #if USE_XDBE 00443 if (!use_xdbe) 00444 #endif 00445 fl_delete_offscreen(myi->other_xid); 00446 } 00447 Fl_Window::hide(); 00448 } 00449 00455 Fl_Double_Window::~Fl_Double_Window() { 00456 hide(); 00457 } 00458 00459 // 00460 // End of "$Id: Fl_Double_Window.cxx 8198 2011-01-06 10:24:58Z manolo $". 00461 //