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