1 /* $Id$
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA.
17
18
19 metacity - (c) 2001 Anders Carlsson, Havoc Pennington
20 xfwm4 - (c) 2002-2015 Olivier Fourdan
21
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/extensions/shape.h>
31 #include <glib.h>
32 #include <gdk/gdk.h>
33 #include <gdk/gdkx.h>
34 #include <gtk/gtk.h>
35 #include <libxfce4util/libxfce4util.h>
36 #include "screen.h"
37 #include "client.h"
38 #include "compositor.h"
39 #include "frame.h"
40 #include "ui_style.h"
41 #include "wireframe.h"
42
43 #ifndef OUTLINE_WIDTH
44 #define OUTLINE_WIDTH 5
45 #endif
46
47 #ifndef OUTLINE_WIDTH_CAIRO
48 #define OUTLINE_WIDTH_CAIRO 2
49 #endif
50
51 static void
wireframeDrawXlib(WireFrame * wireframe,int width,int height)52 wireframeDrawXlib (WireFrame *wireframe, int width, int height)
53 {
54 ScreenInfo *screen_info = wireframe->screen_info;
55
56 wireframe->mapped = FALSE;
57 XUnmapWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
58 XMoveResizeWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow,
59 wireframe->x, wireframe->y, width, height);
60
61 wireframe->width = width;
62 wireframe->height = height;
63
64 if ((wireframe->width > OUTLINE_WIDTH * 2) && (wireframe->height > OUTLINE_WIDTH * 2))
65 {
66 XRectangle xrect;
67 Region inner_xregion;
68 Region outer_xregion;
69
70 inner_xregion = XCreateRegion ();
71 outer_xregion = XCreateRegion ();
72
73 xrect.x = 0;
74 xrect.y = 0;
75 xrect.width = wireframe->width;
76 xrect.height = wireframe->height;
77 XUnionRectWithRegion (&xrect, outer_xregion, outer_xregion);
78
79 xrect.x += OUTLINE_WIDTH;
80 xrect.y += OUTLINE_WIDTH;
81 xrect.width -= OUTLINE_WIDTH * 2;
82 xrect.height -= OUTLINE_WIDTH * 2;
83
84 XUnionRectWithRegion (&xrect, inner_xregion, inner_xregion);
85
86 XSubtractRegion (outer_xregion, inner_xregion, outer_xregion);
87
88 XShapeCombineRegion (myScreenGetXDisplay (screen_info), wireframe->xwindow, ShapeBounding,
89 0, 0, outer_xregion, ShapeSet);
90
91 XDestroyRegion (outer_xregion);
92 XDestroyRegion (inner_xregion);
93 XMapWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
94 wireframe->mapped = TRUE;
95
96 XDrawRectangle (myScreenGetXDisplay (screen_info), wireframe->xwindow,
97 screen_info->box_gc,
98 0, 0, wireframe->width - 1, wireframe->height - 1);
99
100 XDrawRectangle (myScreenGetXDisplay (screen_info), wireframe->xwindow,
101 screen_info->box_gc,
102 OUTLINE_WIDTH - 1, OUTLINE_WIDTH - 1,
103 wireframe->width - 2 * (OUTLINE_WIDTH - 1) - 1,
104 wireframe->height- 2 * (OUTLINE_WIDTH - 1) - 1);
105 }
106 else
107 {
108 /* Unset the shape */
109 XShapeCombineMask (myScreenGetXDisplay (screen_info), wireframe->xwindow,
110 ShapeBounding, 0, 0, None, ShapeSet);
111 XMapWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
112 wireframe->mapped = TRUE;
113
114 XDrawRectangle (myScreenGetXDisplay (screen_info), wireframe->xwindow,
115 screen_info->box_gc,
116 0, 0, wireframe->width - 1, wireframe->height - 1);
117 }
118 }
119
120 static void
wireframeDrawCairo(WireFrame * wireframe,int width,int height)121 wireframeDrawCairo (WireFrame *wireframe, int width, int height)
122 {
123 ScreenInfo *screen_info = wireframe->screen_info;
124
125 XMoveResizeWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow,
126 wireframe->x, wireframe->y, width, height);
127 if (!wireframe->mapped)
128 {
129 XMapWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
130 wireframe->mapped = TRUE;
131 }
132 if ((width == wireframe->width) && (height == wireframe->height))
133 {
134 /* Moving only */
135 return;
136 }
137 wireframe->width = width;
138 wireframe->height = height;
139
140 cairo_xlib_surface_set_size(wireframe->surface, wireframe->width, wireframe->height);
141 XClearWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
142 cairo_set_source_rgba (wireframe->cr, wireframe->red, wireframe->green, wireframe->blue, wireframe->alpha);
143 cairo_paint (wireframe->cr);
144
145 cairo_set_source_rgba (wireframe->cr, wireframe->red, wireframe->green, wireframe->blue, 1.0);
146 cairo_rectangle (wireframe->cr,
147 OUTLINE_WIDTH_CAIRO / 2, OUTLINE_WIDTH_CAIRO / 2,
148 wireframe->width - OUTLINE_WIDTH_CAIRO,
149 wireframe->height - OUTLINE_WIDTH_CAIRO);
150 cairo_stroke (wireframe->cr);
151 /* Force a resize of the compositor window to avoid flickering */
152 compositorResizeWindow (screen_info->display_info, wireframe->xwindow,
153 wireframe->x, wireframe->y,
154 wireframe->width, wireframe->height);
155 }
156
157 void
wireframeUpdate(Client * c,WireFrame * wireframe)158 wireframeUpdate (Client *c, WireFrame *wireframe)
159 {
160 ScreenInfo *screen_info;
161
162 g_return_if_fail (c != NULL);
163 g_return_if_fail (wireframe != NULL);
164 TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
165
166 wireframe->x = frameExtentX (c);
167 wireframe->y = frameExtentY (c);
168
169 screen_info = wireframe->screen_info;
170 if (compositorIsActive (screen_info))
171 {
172 wireframeDrawCairo (wireframe, frameExtentWidth (c), frameExtentHeight (c));
173 }
174 else
175 {
176 wireframeDrawXlib (wireframe, frameExtentWidth (c), frameExtentHeight (c));
177 }
178 XFlush (myScreenGetXDisplay (screen_info));
179 }
180
181 static void
wireframeInitColor(WireFrame * wireframe)182 wireframeInitColor (WireFrame *wireframe)
183 {
184 GdkRGBA rgba;
185
186 if (getUIStyleColor (myScreenGetGtkWidget (wireframe->screen_info), "bg", "selected", &rgba))
187 {
188 wireframe->red = rgba.red;
189 wireframe->green = rgba.green;
190 wireframe->blue = rgba.blue;
191 }
192 }
193
194 WireFrame *
wireframeCreate(Client * c)195 wireframeCreate (Client *c)
196 {
197 ScreenInfo *screen_info;
198 WireFrame *wireframe;
199 XSetWindowAttributes attrs;
200 XVisualInfo xvisual_info;
201 Visual *xvisual;
202 int depth;
203
204 g_return_val_if_fail (c != NULL, None);
205
206 TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
207
208 screen_info = c->screen_info;
209 wireframe = g_new0 (WireFrame, 1);
210 wireframe->screen_info = screen_info;
211 wireframe->mapped = FALSE;
212 wireframe->width = 0;
213 wireframe->height = 0;
214 wireframe->cr = NULL;
215 wireframe->surface = NULL;
216 wireframe->alpha = (compositorIsActive (screen_info) ? 0.5 : 1.0);
217
218 if (compositorIsActive (screen_info) &&
219 XMatchVisualInfo (myScreenGetXDisplay (screen_info), screen_info->screen,
220 32, TrueColor, &xvisual_info))
221 {
222 xvisual = xvisual_info.visual;
223 depth = xvisual_info.depth;
224 wireframe->xcolormap = XCreateColormap (myScreenGetXDisplay (screen_info),
225 screen_info->xroot,
226 xvisual, AllocNone);
227 }
228 else
229 {
230 xvisual = screen_info->visual;
231 depth = screen_info->depth;
232 wireframe->xcolormap = screen_info->cmap;
233 }
234
235 attrs.override_redirect = True;
236 attrs.colormap = wireframe->xcolormap;
237 attrs.background_pixel = BlackPixel (myScreenGetXDisplay (screen_info),
238 screen_info->screen);
239 attrs.border_pixel = BlackPixel (myScreenGetXDisplay (screen_info),
240 screen_info->screen);
241 wireframe->xwindow = XCreateWindow (myScreenGetXDisplay (screen_info), screen_info->xroot,
242 frameExtentX (c), frameExtentY (c),
243 frameExtentWidth (c), frameExtentHeight (c),
244 0, depth, InputOutput, xvisual,
245 CWOverrideRedirect | CWColormap | CWBackPixel | CWBorderPixel,
246 &attrs);
247
248 if (compositorIsActive (screen_info))
249 {
250 /* Cairo */
251 wireframeInitColor (wireframe);
252 wireframe->surface = cairo_xlib_surface_create (myScreenGetXDisplay (screen_info),
253 wireframe->xwindow, xvisual,
254 frameExtentWidth (c), frameExtentHeight (c));
255 wireframe->cr = cairo_create (wireframe->surface);
256 cairo_set_line_width (wireframe->cr, OUTLINE_WIDTH_CAIRO);
257 cairo_set_line_join (wireframe->cr, CAIRO_LINE_JOIN_MITER);
258 }
259
260 wireframeUpdate (c, wireframe);
261
262 return (wireframe);
263 }
264
265 void
wireframeDelete(WireFrame * wireframe)266 wireframeDelete (WireFrame *wireframe)
267 {
268 ScreenInfo *screen_info;
269
270 g_return_if_fail (wireframe != None);
271 TRACE ("entering");
272
273 screen_info = wireframe->screen_info;
274 XUnmapWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
275 if (wireframe->cr)
276 {
277 cairo_destroy (wireframe->cr);
278 }
279 if (wireframe->surface)
280 {
281 cairo_surface_destroy (wireframe->surface);
282 }
283 if (wireframe->xcolormap != screen_info->cmap)
284 {
285 XFreeColormap (myScreenGetXDisplay (screen_info), wireframe->xcolormap);
286 }
287 XDestroyWindow (myScreenGetXDisplay (screen_info), wireframe->xwindow);
288 g_free (wireframe);
289 }
290