1 //
2 // "$Id: fl_scroll_area.cxx 5714 2007-02-25 00:00:49Z matt $"
3 //
4 // Scrolling routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2005 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 // http://www.fltk.org/str.php
26 //
27
28 // Drawing function to move the contents of a rectangle. This is passed
29 // a "callback" which is called to draw rectangular areas that are moved
30 // into the drawing area.
31
32 #include <config.h>
33 #include <FL/Fl.H>
34 #include <FL/x.H>
35 #include <FL/fl_draw.H>
36
37 // scroll a rectangle and redraw the newly exposed portions:
fl_scroll(int X,int Y,int W,int H,int dx,int dy,void (* draw_area)(void *,int,int,int,int),void * data)38 void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
39 void (*draw_area)(void*, int,int,int,int), void* data)
40 {
41 if (!dx && !dy) return;
42 if (dx <= -W || dx >= W || dy <= -H || dy >= H) {
43 // no intersection of old an new scroll
44 draw_area(data,X,Y,W,H);
45 return;
46 }
47 int src_x, src_w, dest_x, clip_x, clip_w;
48 if (dx > 0) {
49 src_x = X;
50 dest_x = X+dx;
51 src_w = W-dx;
52 clip_x = X;
53 clip_w = dx;
54 } else {
55 src_x = X-dx;
56 dest_x = X;
57 src_w = W+dx;
58 clip_x = X+src_w;
59 clip_w = W-src_w;
60 }
61 int src_y, src_h, dest_y, clip_y, clip_h;
62 if (dy > 0) {
63 src_y = Y;
64 dest_y = Y+dy;
65 src_h = H-dy;
66 clip_y = Y;
67 clip_h = dy;
68 } else {
69 src_y = Y-dy;
70 dest_y = Y;
71 src_h = H+dy;
72 clip_y = Y+src_h;
73 clip_h = H-src_h;
74 }
75 #ifdef WIN32
76 typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT);
77 static fl_GetRandomRgn_func fl_GetRandomRgn = 0L;
78 static char first_time = 1;
79
80 // We will have to do some Region magic now, so let's see if the
81 // required function is available (and it should be staring w/Win95)
82 if (first_time) {
83 HMODULE hMod = GetModuleHandle("GDI32.DLL");
84 if (hMod) {
85 fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn");
86 }
87 first_time = 0;
88 }
89
90 // Now check if the source scrolling area is fully visible.
91 // If it is, we will do a quick scroll and just update the
92 // newly exposed area. If it is not, we go the safe route and
93 // re-render the full area instead.
94 // Note 1: we could go and find the areas that are actually
95 // obscured and recursively call fl_scroll for the newly found
96 // rectangles. However, this practice would rely on the
97 // elements of the undocumented Rgn structure.
98 // Note 2: although this method should take care of most
99 // multi-screen solutions, it will not solve issues scrolling
100 // from a different resolution screen onto another.
101 // Note 3: this has been tested with image maps, too.
102 if (fl_GetRandomRgn) {
103 // get the DC region minus all overlapping windows
104 HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0);
105 fl_GetRandomRgn(fl_gc, sys_rgn, 4);
106 // now get the source scrolling rectangle
107 HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h);
108 POINT offset = { 0, 0 };
109 if (GetDCOrgEx(fl_gc, &offset)) {
110 OffsetRgn(src_rgn, offset.x, offset.y);
111 }
112 // see if all source pixels are available in the system region
113 // Note: we could be a bit more merciful and subtract the
114 // scroll destination region as well.
115 HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0);
116 int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF);
117 DeleteObject(dst_rgn);
118 DeleteObject(src_rgn);
119 DeleteObject(sys_rgn);
120 if (r!=NULLREGION) {
121 draw_area(data,X,Y,W,H);
122 return;
123 }
124 }
125
126 // Great, we can do an accelerated scroll insteasd of re-rendering
127 BitBlt(fl_gc, dest_x, dest_y, src_w, src_h, fl_gc, src_x, src_y,SRCCOPY);
128
129 #elif defined(__APPLE_QD__)
130 Rect src = { src_y, src_x, src_y+src_h, src_x+src_w };
131 Rect dst = { dest_y, dest_x, dest_y+src_h, dest_x+src_w };
132 static RGBColor bg = { 0xffff, 0xffff, 0xffff }; RGBBackColor( &bg );
133 static RGBColor fg = { 0x0000, 0x0000, 0x0000 }; RGBForeColor( &fg );
134 CopyBits( GetPortBitMapForCopyBits( GetWindowPort(fl_window) ),
135 GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), &src, &dst, srcCopy, 0L);
136 #elif defined(__APPLE_QUARTZ__)
137 // warning: there does not seem to be an equivalent to this function in Quartz
138 // ScrollWindowRect is a QuickDraw function and won't work here.
139 // Since on OS X all windows are fully double buffered, we need not
140 // worry about offscreen or obscured areas
141 Rect src = { src_y, src_x, src_y+src_h, src_x+src_w };
142 Rect dst = { dest_y, dest_x, dest_y+src_h, dest_x+src_w };
143 static RGBColor bg = { 0xffff, 0xffff, 0xffff }; RGBBackColor( &bg );
144 static RGBColor fg = { 0x0000, 0x0000, 0x0000 }; RGBForeColor( &fg );
145 CopyBits( GetPortBitMapForCopyBits( GetWindowPort(fl_window) ),
146 GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), &src, &dst, srcCopy, 0L);
147 #else
148 XCopyArea(fl_display, fl_window, fl_window, fl_gc,
149 src_x, src_y, src_w, src_h, dest_x, dest_y);
150 // we have to sync the display and get the GraphicsExpose events! (sigh)
151 for (;;) {
152 XEvent e; XWindowEvent(fl_display, fl_window, ExposureMask, &e);
153 if (e.type == NoExpose) break;
154 // otherwise assumme it is a GraphicsExpose event:
155 draw_area(data, e.xexpose.x, e.xexpose.y,
156 e.xexpose.width, e.xexpose.height);
157 if (!e.xgraphicsexpose.count) break;
158 }
159 #endif
160 if (dx) draw_area(data, clip_x, dest_y, clip_w, src_h);
161 if (dy) draw_area(data, X, clip_y, W, clip_h);
162 }
163
164 //
165 // End of "$Id: fl_scroll_area.cxx 5714 2007-02-25 00:00:49Z matt $".
166 //
167