1 /* backing.c - save, extend, and restore contents of root window
2 
3    Copyright 2001 Carl Worth
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 */
15 
16 #include <stdio.h>
17 #include <X11/Xlib.h>
18 
19 #include "backing.h"
20 
21 #ifdef DMALLOC
22 #include "dmalloc.h"
23 #endif
24 
backing_init(backing_t * backing,Display * dpy,Window root,int width,int height,int depth)25 int backing_init(backing_t *backing, Display *dpy, Window root, int width, int height, int depth)
26 {
27     XRenderPictFormat templ;
28     int screen = DefaultScreen(dpy);
29     unsigned long gcm;
30     XGCValues gcv;
31 
32     backing->dpy = dpy;
33     backing->root = root;
34     backing->active = 0;
35 
36     gcm = 0;
37     gcm |= GCSubwindowMode; gcv.subwindow_mode = IncludeInferiors;
38     backing->gc = XCreateGC(backing->dpy, backing->root, gcm, &gcv);
39 
40     backing->root_pixmap = 0;
41     backing->brush_pixmap = 0;
42     backing->total_width = width;
43     backing->total_height = height;
44     backing->depth = depth;
45     backing->root_pict = 0;
46     backing->brush_pict = 0;
47 
48     backing->root_format = XRenderFindVisualFormat(dpy,DefaultVisual(dpy, screen));
49 
50     templ.type = PictTypeDirect;
51     templ.depth = 32;
52     templ.direct.alpha = 24;
53     templ.direct.alphaMask = 0xff;
54     templ.direct.red = 16;
55     templ.direct.redMask = 0xff;
56     templ.direct.green = 8;
57     templ.direct.greenMask = 0xff;
58     templ.direct.blue = 0;
59     templ.direct.blueMask = 0xff;
60     backing->brush_format = XRenderFindFormat (dpy,
61 					       PictFormatType|
62 					       PictFormatDepth|
63 					       PictFormatAlpha|
64 					       PictFormatAlphaMask|
65 					       PictFormatRed|
66 					       PictFormatRedMask|
67 					       PictFormatGreen|
68 					       PictFormatGreenMask|
69 					       PictFormatBlue|
70 					       PictFormatBlueMask,
71 					       &templ, 0);
72 
73     return 0;
74 }
75 
backing_deinit(backing_t * backing)76 void backing_deinit(backing_t *backing)
77 {
78     backing->active = 0;
79     XFreeGC(backing->dpy, backing->gc);
80     if (backing->root_pixmap) {
81 	XFreePixmap(backing->dpy, backing->root_pixmap);
82 	backing->root_pixmap = 0;
83 
84 	XRenderFreePicture(backing->dpy, backing->root_pict);
85 	backing->root_pict = 0;
86     }
87     if (backing->brush_pixmap) {
88 	XFreePixmap(backing->dpy, backing->brush_pixmap);
89 	backing->brush_pixmap = 0;
90 
91 	XRenderFreePicture(backing->dpy, backing->brush_pict);
92 	backing->brush_pict = 0;
93     }
94 }
95 
backing_save(backing_t * backing,int x,int y)96 int backing_save(backing_t *backing, int x, int y)
97 {
98     if (backing->active == 0) {
99 	backing_reconfigure(backing,
100 			    backing->total_width,
101 			    backing->total_height,
102 			    backing->depth);
103 	backing->active = 1;
104 
105 	backing->x = BACKING_INC * (x / BACKING_INC);
106 	backing->y = BACKING_INC * (y / BACKING_INC);
107 	backing->width = BACKING_INC;
108 	backing->height = BACKING_INC;
109 	XCopyArea(backing->dpy, backing->root,
110 		  backing->root_pixmap, backing->gc,
111 		  backing->x, backing->y,
112 		  backing->width, backing->height,
113 		  backing->x, backing->y);
114     } else {
115 	if (x >= backing->x + backing->width) {
116 	    int new_max_x, width_inc;
117 	    new_max_x = BACKING_INC * ((x / BACKING_INC) + 1);
118 	    width_inc = new_max_x - (backing->x + backing->width);
119 	    XCopyArea(backing->dpy, backing->root,
120 		      backing->root_pixmap, backing->gc,
121 		      backing->x + backing->width, backing->y,
122 		      width_inc, backing->height,
123 		      backing->x + backing->width, backing->y);
124 	    backing->width += width_inc;
125 	}
126 	if (x < backing->x) {
127 	    int new_x, width_inc;
128 	    new_x = BACKING_INC * (x / BACKING_INC);
129 	    width_inc = backing->x - new_x;
130 	    XCopyArea(backing->dpy, backing->root,
131 		      backing->root_pixmap, backing->gc,
132 		      new_x, backing->y,
133 		      width_inc, backing->height,
134 		      new_x, backing->y);
135 	    backing->width += width_inc;
136 	    backing->x = new_x;
137 	}
138 	if (y >= backing->y + backing->height) {
139 	    int new_max_y, height_inc;
140 	    new_max_y = BACKING_INC * ((y / BACKING_INC) + 1);
141 	    height_inc = new_max_y - (backing->y + backing->height);
142 	    XCopyArea(backing->dpy, backing->root,
143 		      backing->root_pixmap, backing->gc,
144 		      backing->x, backing->y + backing->height,
145 		      backing->width, height_inc,
146 		      backing->x, backing->y + backing->height);
147 	    backing->height += height_inc;
148 	}
149 	if (y < backing->y) {
150 	    int new_y, height_inc;
151 	    new_y = BACKING_INC * (y / BACKING_INC);
152 	    height_inc = backing->y - new_y;
153 	    XCopyArea(backing->dpy, backing->root,
154 		      backing->root_pixmap, backing->gc,
155 		      backing->x, new_y,
156 		      backing->width, height_inc,
157 		      backing->x, new_y);
158 	    backing->height += height_inc;
159 	    backing->y = new_y;
160 	}
161     }
162     return 0;
163 }
164 
backing_restore(backing_t * backing)165 int backing_restore(backing_t *backing)
166 {
167     XCopyArea(backing->dpy, backing->root_pixmap,
168 	      backing->root, backing->gc,
169 	      backing->x, backing->y,
170 	      backing->width, backing->height,
171 	      backing->x, backing->y);
172     backing->active = 0;
173 
174     XFreePixmap(backing->dpy, backing->root_pixmap);
175     backing->root_pixmap = 0;
176     XRenderFreePicture(backing->dpy, backing->root_pict);
177     backing->root_pict = 0;
178 
179     XFreePixmap(backing->dpy, backing->brush_pixmap);
180     backing->brush_pixmap = 0;
181     XRenderFreePicture(backing->dpy, backing->brush_pict);
182     backing->brush_pict = 0;
183 
184     return 0;
185 }
186 
backing_reconfigure(backing_t * backing,int width,int height,int depth)187 int backing_reconfigure(backing_t *backing, int width, int height, int depth)
188 {
189     XRenderColor color;
190     XRenderPictureAttributes attr;
191     backing_t old_backing = *backing;
192 
193     backing->total_width = width;
194     backing->total_height = height;
195     backing->depth = depth;
196 
197     backing->root_pixmap = XCreatePixmap(backing->dpy, backing->root,
198 					 backing->total_width,
199 					 backing->total_height,
200 					 depth);
201     attr.subwindow_mode = IncludeInferiors;
202     backing->root_pict = XRenderCreatePicture(backing->dpy,
203 					      backing->root,
204 					      backing->root_format,
205 					      CPSubwindowMode,
206 					      &attr);
207 
208     backing->brush_pixmap = XCreatePixmap(backing->dpy, backing->root,
209 					  backing->total_width,
210 					  backing->total_height,
211 					  32);
212     backing->brush_pict = XRenderCreatePicture(backing->dpy,
213 					       backing->brush_pixmap,
214 					       backing->brush_format,
215 					       0, 0);
216 
217     color.red = 0;
218     color.green = 0;
219     color.blue = 0;
220     color.alpha = 0;
221     XRenderFillRectangle(backing->dpy,
222 			 PictOpSrc, backing->brush_pict, &color,
223 			 0, 0, backing->total_width, backing->total_height);
224 
225     if (old_backing.root_pixmap) {
226 	if (old_backing.depth == depth) {
227 	    XCopyArea(backing->dpy, old_backing.root_pixmap,
228 		      backing->root_pixmap, backing->gc,
229 		      old_backing.x, old_backing.y,
230 		      old_backing.width, old_backing.height,
231 		      old_backing.x, old_backing.y);
232 	}
233 	XFreePixmap(old_backing.dpy, old_backing.root_pixmap);
234 	old_backing.root_pixmap = 0;
235 	XRenderFreePicture(old_backing.dpy, old_backing.root_pict);
236 	old_backing.root_pict = 0;
237     }
238     if (old_backing.brush_pixmap) {
239 	XRenderComposite(backing->dpy,
240 			 PictOpSrc,
241 			 old_backing.brush_pict, None, backing->brush_pict,
242 			 0, 0, 0, 0, 0, 0,
243 			 old_backing.total_width, old_backing.total_height);
244 	XFreePixmap(old_backing.dpy, old_backing.brush_pixmap);
245 	old_backing.brush_pixmap = 0;
246 	XRenderFreePicture(old_backing.dpy, old_backing.brush_pict);
247 	old_backing.brush_pict = 0;
248     }
249 
250     return 0;
251 }
252 
253