Merge lp:~3v1n0/compiz/support-desktop-average-colors into lp:compiz

Proposed by Marco Trevisan (Treviño) on 2017-06-30
Status: Merged
Approved by: Andrea Azzarone on 2017-06-30
Approved revision: 4150
Merged at revision: 4125
Proposed branch: lp:~3v1n0/compiz/support-desktop-average-colors
Merge into: lp:compiz
Prerequisite: lp:~3v1n0/compiz/resize-lowgfx-fixes
Diff against target: 1075 lines (+506/-96)
17 files modified
include/core/abiversion.h (+1/-1)
include/core/atoms.h (+2/-0)
include/core/screen.h (+7/-1)
include/core/string.h (+3/-0)
plugins/grid/grid.xml.in (+5/-0)
plugins/grid/src/grid.cpp (+42/-9)
plugins/move/move.xml.in (+10/-0)
plugins/move/src/move.cpp (+142/-61)
plugins/move/src/move.h (+1/-1)
plugins/resize/resize.xml.in (+10/-0)
plugins/resize/src/resize.cpp (+69/-18)
src/atoms.cpp (+4/-0)
src/event.cpp (+5/-0)
src/privatescreen.h (+6/-0)
src/privatescreen/tests/test-privatescreen.cpp (+2/-0)
src/screen.cpp (+136/-5)
src/string/src/string.cpp (+61/-0)
To merge this branch: bzr merge lp:~3v1n0/compiz/support-desktop-average-colors
Reviewer Review Type Date Requested Status
Andrea Azzarone 2017-06-30 Approve on 2017-06-30
Review via email: mp+326573@code.launchpad.net

Commit Message

Screen: add averageColor to get the current desktop average color

We get the value from the root window and we parse it using regex.
Also use this in 'move', 'resize' and 'grid' plugins by default, doing the
appropriate lightening / darkening to make this working properly
on the desktop surface

To post a comment you must log in.
4150. By Marco Trevisan (Treviño) on 2017-06-30

move, resize: fix compilation issue in GLES platforms

Andrea Azzarone (azzar1) wrote :

LGTM.

review: Approve
4151. By Marco Trevisan (Treviño) on 2017-07-03

move, resize: fix damaging glitches with bigger border

4152. By Marco Trevisan (Treviño) on 2017-07-03

String: fix typo in regex match check

Don't miss the values... regex_match returns true if valid

4153. By Marco Trevisan (Treviño) on 2017-07-03

move: enable glPaintOutput only if we've a window to move and damage it on init

4154. By Marco Trevisan (Treviño) on 2017-07-03

move: use the same code for damaging the moving rectangle on init and on updates

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/core/abiversion.h'
2--- include/core/abiversion.h 2015-10-13 11:33:31 +0000
3+++ include/core/abiversion.h 2017-07-03 15:16:04 +0000
4@@ -5,6 +5,6 @@
5 # error Conflicting definitions of CORE_ABIVERSION
6 #endif
7
8-#define CORE_ABIVERSION 20151010
9+#define CORE_ABIVERSION 20170630
10
11 #endif // COMPIZ_ABIVERSION_H
12
13=== modified file 'include/core/atoms.h'
14--- include/core/atoms.h 2015-02-17 14:54:10 +0000
15+++ include/core/atoms.h 2017-07-03 15:16:04 +0000
16@@ -158,6 +158,8 @@
17
18 extern Atom startupId;
19
20+ extern Atom gnomeRepresentativeColors;
21+
22 void init (Display *dpy);
23 };
24
25
26=== modified file 'include/core/screen.h'
27--- include/core/screen.h 2016-04-26 12:42:39 +0000
28+++ include/core/screen.h 2017-07-03 15:16:04 +0000
29@@ -156,6 +156,8 @@
30 virtual void addSupportedAtoms (std::vector<Atom>& atoms);
31
32 virtual void cursorChangeNotify (const CompString& theme, int size);
33+
34+ virtual void averageColorChangeNotify (const unsigned short *color);
35 };
36
37 namespace compiz { namespace private_screen {
38@@ -221,7 +223,7 @@
39 }
40
41 class CompScreen :
42- public WrapableHandler<ScreenInterface, 19>,
43+ public WrapableHandler<ScreenInterface, 20>,
44 public PluginClassStorage, // TODO should be an interface here
45 public CompSize,
46 public virtual ::compiz::DesktopWindowCount,
47@@ -273,6 +275,8 @@
48 std::vector<Atom>& atoms);
49 WRAPABLE_HND (18, ScreenInterface, void, cursorChangeNotify,
50 const CompString&, int);
51+ WRAPABLE_HND (19, ScreenInterface, void, averageColorChangeNotify,
52+ const unsigned short *);
53
54 unsigned int allocPluginClassIndex ();
55 void freePluginClassIndex (unsigned int index);
56@@ -418,6 +422,7 @@
57 virtual CompWindow * getTopServerWindow() const = 0;
58 virtual CoreOptions& getCoreOptions() = 0;
59 virtual Colormap colormap() const = 0;
60+ virtual const unsigned short * averageColor() const = 0;
61 virtual void setCurrentDesktop (unsigned int desktop) = 0;
62 virtual Window activeWindow() const = 0;
63 virtual void updatePassiveButtonGrabs(Window serverFrame) = 0;
64@@ -453,6 +458,7 @@
65 virtual void _matchPropertyChanged(CompWindow *) = 0;
66 virtual void _outputChangeNotify() = 0;
67 virtual void _cursorChangeNotify(const CompString&, int) = 0;
68+ virtual void _averageColorChangeNotify(const unsigned short*) = 0;
69 };
70
71 #endif
72
73=== modified file 'include/core/string.h'
74--- include/core/string.h 2011-10-31 13:51:00 +0000
75+++ include/core/string.h 2017-07-03 15:16:04 +0000
76@@ -28,12 +28,15 @@
77
78 #include <string>
79 #include <list>
80+#include <vector>
81 #include <cstdarg>
82
83 typedef std::string CompString;
84 typedef std::list<CompString> CompStringList;
85+typedef std::vector<CompString> CompStringVector;
86
87 CompString compPrintf (const char *format, ...);
88 CompString compPrintf (const char *format, va_list ap);
89+CompStringVector compGetRegexMatches (const CompString& regexStr, const CompString& string);
90
91 #endif
92
93=== modified file 'plugins/grid/grid.xml.in'
94--- plugins/grid/grid.xml.in 2016-09-07 12:26:21 +0000
95+++ plugins/grid/grid.xml.in 2017-07-03 15:16:04 +0000
96@@ -569,6 +569,11 @@
97 <default>350</default>
98 <min>0</min>
99 </option>
100+ <option name="use_desktop_average_color" type="bool">
101+ <_short>Use Desktop average color</_short>
102+ <_long>Try to use the desktop average color if defined by your DE.</_long>
103+ <default>true</default>
104+ </option>
105 <option name="outline_color" type="color">
106 <_short>Preview Outline Color</_short>
107 <_long>Color and opacity of the resize indicator preview outline.</_long>
108
109=== modified file 'plugins/grid/src/grid.cpp'
110--- plugins/grid/src/grid.cpp 2017-07-03 15:16:04 +0000
111+++ plugins/grid/src/grid.cpp 2017-07-03 15:16:04 +0000
112@@ -508,7 +508,8 @@
113 GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
114 GLfloat vertexData[12];
115 GLushort colorData[4];
116- GLushort *color;
117+ unsigned short *color, *fillColor, *outlineColor;
118+ unsigned short averageFillColor[4], averageOutlineColor[4];
119 GLboolean isBlendingEnabled;
120 bool blend = !optionGetDisableBlend ();
121
122@@ -527,13 +528,45 @@
123 glEnable (GL_BLEND);
124 }
125
126+ fillColor = optionGetFillColor ();
127+ outlineColor = optionGetOutlineColor ();
128+
129+ if (optionGetUseDesktopAverageColor ())
130+ {
131+ const unsigned short *averageColor = screen->averageColor ();
132+
133+ if (averageColor)
134+ {
135+ memcpy (averageFillColor, averageColor, 4 * sizeof (unsigned short));
136+ averageFillColor[3] = MaxUShortFloat * 0.6;
137+ fillColor = averageFillColor;
138+
139+ // Generate a lighter color based on border to create more contrast
140+ unsigned int averageColorLevel = (averageColor[0] + averageColor[1] + averageColor[2]) / 3;
141+ unsigned short *oc = averageOutlineColor;
142+
143+ float colorMultiplier;
144+ if (averageColorLevel > MaxUShortFloat * 0.3)
145+ colorMultiplier = 0.7; // make it darker
146+ else
147+ colorMultiplier = 2.0; // make it lighter
148+
149+ oc[3] = averageColor[3];
150+ oc[0] = MIN(MaxUShortFloat, ((float) averageColor[0]) * colorMultiplier) * oc[3] / MaxUShortFloat;
151+ oc[1] = MIN(MaxUShortFloat, ((float) averageColor[1]) * colorMultiplier) * oc[3] / MaxUShortFloat;
152+ oc[2] = MIN(MaxUShortFloat, ((float) averageColor[2]) * colorMultiplier) * oc[3] / MaxUShortFloat;
153+
154+ outlineColor = averageOutlineColor;
155+ }
156+ }
157+
158 for (iter = animations.begin (); iter != animations.end () && animating; ++iter)
159 {
160 Animation& anim = *iter;
161
162 float curve = powf (CURVE_ANIMATION, -anim.progress);
163- float alpha = blend ? (optionGetFillColorAlpha () / MaxUShortFloat) * anim.opacity : 0.85;
164- color = optionGetFillColor ();
165+ float alpha = blend ? (fillColor[3] / MaxUShortFloat) * anim.opacity : 0.85;
166+ color = fillColor;
167
168 colorData[0] = alpha * color[0];
169 colorData[1] = alpha * color[1];
170@@ -570,8 +603,8 @@
171 anim.currentRect.height () - 2);
172
173 /* draw outline */
174- alpha = blend ? (optionGetOutlineColorAlpha () / MaxUShortFloat) * anim.opacity : 1;
175- color = optionGetOutlineColor ();
176+ alpha = blend ? (outlineColor[3] / MaxUShortFloat) * anim.opacity : 1;
177+ color = outlineColor;
178
179 colorData[0] = alpha * color[0];
180 colorData[1] = alpha * color[1];
181@@ -603,8 +636,8 @@
182 if (!animating)
183 {
184 /* draw filled rectangle */
185- float alpha = blend ? optionGetFillColorAlpha () / MaxUShortFloat : 0.85;
186- color = optionGetFillColor ();
187+ float alpha = blend ? fillColor[3] / MaxUShortFloat : 0.85;
188+ color = fillColor;
189
190 colorData[0] = alpha * color[0];
191 colorData[1] = alpha * color[1];
192@@ -638,8 +671,8 @@
193 rect.height () - 2);
194
195 /* draw outline */
196- alpha = optionGetOutlineColorAlpha () / MaxUShortFloat;
197- color = optionGetOutlineColor ();
198+ alpha = outlineColor[3] / MaxUShortFloat;
199+ color = outlineColor;
200
201 colorData[0] = alpha * color[0];
202 colorData[1] = alpha * color[1];
203
204=== modified file 'plugins/move/move.xml.in'
205--- plugins/move/move.xml.in 2016-09-07 12:25:04 +0000
206+++ plugins/move/move.xml.in 2017-07-03 15:16:04 +0000
207@@ -92,6 +92,16 @@
208 <_name>Rectangle</_name>
209 </desc>
210 </option>
211+ <option name="increase_border_contrast" type="bool">
212+ <_short>Use a double-border in 'Rectangle' and 'Outline' modes</_short>
213+ <_long>Increase the contrast of the border using a lighter color.</_long>
214+ <default>true</default>
215+ </option>
216+ <option name="use_desktop_average_color" type="bool">
217+ <_short>Use Desktop average colors</_short>
218+ <_long>Try to use the desktop average color if defined by your DE (overrides custom colors).</_long>
219+ <default>true</default>
220+ </option>
221 <option name="border_color" type="color">
222 <_short>Border Color</_short>
223 <_long>Border color used for outline and rectangle moving modes</_long>
224
225=== modified file 'plugins/move/src/move.cpp'
226--- plugins/move/src/move.cpp 2017-07-03 15:16:04 +0000
227+++ plugins/move/src/move.cpp 2017-07-03 15:16:04 +0000
228@@ -34,6 +34,9 @@
229
230 COMPIZ_PLUGIN_20090315 (move, MovePluginVTable)
231
232+static const int defaultBorderWidth = 2;
233+static const int biggerBorderWidthMultiplier = 2;
234+
235 static bool
236 moveInitiate (CompAction *action,
237 CompAction::State state,
238@@ -43,14 +46,6 @@
239
240 MOVE_SCREEN (screen);
241
242- if (ms->optionGetMode () != MoveOptions::ModeNormal)
243- {
244- ms->gScreen->glPaintOutputSetEnabled (ms, true);
245- ms->paintRect = true;
246- ms->rectX = 0;
247- ms->rectY = 0;
248- }
249-
250 Window xid = CompOption::getIntOptionNamed (options, "window");
251
252 w = screen->findWindow (xid);
253@@ -150,6 +145,19 @@
254 s->warpPointer (xRoot - pointerX, yRoot - pointerY);
255 }
256
257+ if (ms->optionGetMode () != MoveOptions::ModeNormal)
258+ {
259+ Box box;
260+
261+ ms->gScreen->glPaintOutputSetEnabled (ms, true);
262+ ms->paintRect = true;
263+ ms->rectX = 0;
264+ ms->rectY = 0;
265+
266+ if (ms->getMovingRectangle (&box))
267+ ms->damageMovingRectangle (&box);
268+ }
269+
270 if (ms->moveOpacity != OPAQUE)
271 {
272 MOVE_WINDOW (w);
273@@ -797,6 +805,61 @@
274 return true;
275 }
276
277+bool
278+MoveScreen::damageMovingRectangle (BoxPtr pBox)
279+{
280+ CompRegion damageRegion;
281+ int borderWidth;
282+
283+ if (!cScreen || !pBox)
284+ return false;
285+
286+ borderWidth = defaultBorderWidth;
287+
288+ if (optionGetIncreaseBorderContrast ())
289+ borderWidth *= biggerBorderWidthMultiplier;
290+
291+ if (optionGetMode () == MoveOptions::ModeRectangle)
292+ {
293+ CompRect damage (pBox->x1 - borderWidth,
294+ pBox->y1 - borderWidth,
295+ pBox->x2 - pBox->x1 + borderWidth * 2,
296+ pBox->y2 - pBox->y1 + borderWidth * 2);
297+ damageRegion += damage;
298+ }
299+ else if (optionGetMode () == MoveOptions::ModeOutline)
300+ {
301+ // Top
302+ damageRegion += CompRect (pBox->x1 - borderWidth,
303+ pBox->y1 - borderWidth,
304+ pBox->x2 - pBox->x1 + borderWidth * 2,
305+ borderWidth * 2);
306+ // Right
307+ damageRegion += CompRect (pBox->x2 - borderWidth,
308+ pBox->y1 - borderWidth,
309+ borderWidth + borderWidth / 2,
310+ pBox->y2 - pBox->y1 + borderWidth * 2);
311+ // Bottom
312+ damageRegion += CompRect (pBox->x1 - borderWidth,
313+ pBox->y2 - borderWidth,
314+ pBox->x2 - pBox->x1 + borderWidth * 2,
315+ borderWidth * 2);
316+ // Left
317+ damageRegion += CompRect (pBox->x1 - borderWidth,
318+ pBox->y1 - borderWidth,
319+ borderWidth + borderWidth / 2,
320+ pBox->y2 - pBox->y1 + borderWidth * 2);
321+ }
322+
323+ if (!damageRegion.isEmpty ())
324+ {
325+ cScreen->damageRegion (damageRegion);
326+ return true;
327+ }
328+
329+ return false;
330+}
331+
332 bool MoveScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
333 const GLMatrix &transform,
334 const CompRegion &region,
335@@ -833,11 +896,31 @@
336 const float MaxUShortFloat = MaxUShort;
337 GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
338 GLMatrix sTransform (transform);
339+ bool usingAverageColors = false;
340
341 GLfloat vertexData[12];
342 GLfloat vertexData2[24];
343- GLushort fc[4], bc[4];
344+ GLushort fc[4], bc[4], averageFillColor[4];
345 GLint origSrc, origDst;
346+#ifdef USE_GLES
347+ GLint origSrcAlpha, origDstAlpha;
348+#endif
349+
350+ if (optionGetUseDesktopAverageColor ())
351+ {
352+ const unsigned short *averageColor = screen->averageColor ();
353+
354+ if (averageColor)
355+ {
356+ usingAverageColors = true;
357+ borderColor = const_cast<unsigned short *>(averageColor);
358+ memcpy (averageFillColor, averageColor, 4 * sizeof (unsigned short));
359+ averageFillColor[3] = MaxUShort * 0.6;
360+
361+ if (fillColor)
362+ fillColor = averageFillColor;
363+ }
364+ }
365
366 bool blend = optionGetBlend ();
367
368@@ -850,7 +933,6 @@
369 if (blend)
370 {
371 #ifdef USE_GLES
372- GLint origSrcAlpha, origDstAlpha;
373 glGetIntegerv (GL_BLEND_SRC_RGB, &origSrc);
374 glGetIntegerv (GL_BLEND_DST_RGB, &origDst);
375 glGetIntegerv (GL_BLEND_SRC_ALPHA, &origSrcAlpha);
376@@ -861,11 +943,6 @@
377 #endif
378 }
379
380- bc[3] = blend ? ((float) borderColor[3] / MaxUShortFloat) : MaxUShortFloat;
381- bc[0] = ((float) borderColor[0] / MaxUShortFloat) * bc[3];
382- bc[1] = ((float) borderColor[1] / MaxUShortFloat) * bc[3];
383- bc[2] = ((float) borderColor[2] / MaxUShortFloat) * bc[3];
384-
385 vertexData[0] = box.x1;
386 vertexData[1] = box.y1;
387 vertexData[2] = 0.0f;
388@@ -928,59 +1005,63 @@
389 }
390
391 /* draw outline */
392- static const int borderWidth = 2;
393-
394- glLineWidth (borderWidth);
395+ int borderWidth = defaultBorderWidth;
396+
397+ if (optionGetIncreaseBorderContrast() || usingAverageColors)
398+ {
399+ // Generate a lighter color based on border to create more contrast
400+ unsigned int averageColorLevel = (borderColor[0] + borderColor[1] + borderColor[2]) / 3;
401+
402+ float colorMultiplier;
403+ if (averageColorLevel > MaxUShort * 0.3)
404+ colorMultiplier = 0.7; // make it darker
405+ else
406+ colorMultiplier = 2.0; // make it lighter
407+
408+ bc[3] = borderColor[3];
409+ bc[0] = MIN(MaxUShortFloat, ((float) borderColor[0]) * colorMultiplier) * bc[3] / MaxUShortFloat;
410+ bc[1] = MIN(MaxUShortFloat, ((float) borderColor[1]) * colorMultiplier) * bc[3] / MaxUShortFloat;
411+ bc[2] = MIN(MaxUShortFloat, ((float) borderColor[2]) * colorMultiplier) * bc[3] / MaxUShortFloat;
412+
413+ if (optionGetIncreaseBorderContrast ())
414+ {
415+ borderWidth *= biggerBorderWidthMultiplier;
416+
417+ glLineWidth (borderWidth);
418+ streamingBuffer->begin (GL_LINES);
419+ streamingBuffer->addVertices (8, &vertexData2[0]);
420+ streamingBuffer->addColors (1, bc);
421+ streamingBuffer->end ();
422+ streamingBuffer->render (sTransform);
423+ } else if (usingAverageColors) {
424+ borderColor = bc;
425+ }
426+ }
427+
428+ bc[3] = blend ? borderColor[3] : MaxUShortFloat;
429+ bc[0] = borderColor[0] * bc[3] / MaxUShortFloat;
430+ bc[1] = borderColor[1] * bc[3] / MaxUShortFloat;
431+ bc[2] = borderColor[2] * bc[3] / MaxUShortFloat;
432+
433+ glLineWidth (defaultBorderWidth);
434 streamingBuffer->begin (GL_LINES);
435- streamingBuffer->addColors (1, borderColor);
436+ streamingBuffer->addColors (1, bc);
437 streamingBuffer->addVertices (8, &vertexData2[0]);
438 streamingBuffer->end ();
439 streamingBuffer->render (sTransform);
440
441 if (blend)
442 {
443- glEnable (GL_BLEND);
444- glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
445- }
446-
447- if (cScreen)
448- {
449- CompRegion damageRegion;
450-
451- if (optionGetMode () == MoveOptions::ModeOutline)
452- {
453- // Top
454- damageRegion += CompRect (box.x1 - borderWidth,
455- box.y1 - borderWidth,
456- box.x2 - box.x1 + borderWidth * 2,
457- borderWidth + 1);
458- // Right
459- damageRegion += CompRect (box.x2 - borderWidth,
460- box.y1 - borderWidth,
461- borderWidth + 1,
462- box.y2 - box.y1 + borderWidth * 2);
463- // Bottom
464- damageRegion += CompRect (box.x1 - borderWidth,
465- box.y2 - borderWidth,
466- box.x2 - box.x1 + borderWidth * 2,
467- borderWidth + 1);
468- // Left
469- damageRegion += CompRect (box.x1 - borderWidth,
470- box.y1 - borderWidth,
471- borderWidth + 1,
472- box.y2 - box.y1 + borderWidth * 2);
473- }
474- else
475- {
476- CompRect damage (box.x1 - borderWidth,
477- box.y1 - borderWidth,
478- box.x2 - box.x1 + borderWidth * 2,
479- box.y2 - box.y1 + borderWidth * 2);
480- damageRegion += damage;
481- }
482-
483- cScreen->damageRegion (damageRegion);
484- }
485+ glDisable (GL_BLEND);
486+#ifdef USE_GLES
487+ glBlendFuncSeparate (origSrc, origDst,
488+ origSrcAlpha, origDstAlpha);
489+#else
490+ glBlendFunc (origSrc, origDst);
491+#endif
492+ }
493+
494+ damageMovingRectangle (&box);
495
496 return true;
497 }
498
499=== modified file 'plugins/move/src/move.h'
500--- plugins/move/src/move.h 2017-07-03 15:16:04 +0000
501+++ plugins/move/src/move.h 2017-07-03 15:16:04 +0000
502@@ -75,7 +75,7 @@
503 unsigned int);
504
505 bool getMovingRectangle (BoxPtr pbox);
506- void damageMovingRectangle (BoxPtr pbox);
507+ bool damageMovingRectangle (BoxPtr pbox);
508 bool glPaintMovingRectangle (const GLMatrix &transform, CompOutput *output, unsigned short *borderColor, unsigned short *fillColor);
509
510 CompWindow *w;
511
512=== modified file 'plugins/resize/resize.xml.in'
513--- plugins/resize/resize.xml.in 2017-07-03 15:16:04 +0000
514+++ plugins/resize/resize.xml.in 2017-07-03 15:16:04 +0000
515@@ -58,6 +58,16 @@
516 <long>Maximizes the window vertically if the top or bottom screen edge is hit while resizing</long>
517 <default>true</default>
518 </option>
519+ <option name="increase_border_contrast" type="bool">
520+ <_short>Use a double-border in 'Rectangle' and 'Outline' modes</_short>
521+ <_long>Increase the contrast of the border using a lighter color.</_long>
522+ <default>true</default>
523+ </option>
524+ <option name="use_desktop_average_color" type="bool">
525+ <_short>Use Desktop average colors</_short>
526+ <_long>Try to use the desktop average color if defined by your DE (overrides custom colors).</_long>
527+ <default>true</default>
528+ </option>
529 <option name="border_color" type="color">
530 <_short>Border Color</_short>
531 <_long>Border color used for outline and rectangle resize modes</_long>
532
533=== modified file 'plugins/resize/src/resize.cpp'
534--- plugins/resize/src/resize.cpp 2017-07-03 15:16:04 +0000
535+++ plugins/resize/src/resize.cpp 2017-07-03 15:16:04 +0000
536@@ -70,8 +70,8 @@
537
538 static bool
539 resizeTerminate (CompAction *action,
540- CompAction::State state,
541- CompOption::Vector &options)
542+ CompAction::State state,
543+ CompOption::Vector &options)
544 {
545 RESIZE_SCREEN (screen);
546 return rs->logic.terminateResize(action, state, options);
547@@ -87,14 +87,34 @@
548 GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
549 const unsigned short MaxUShort = std::numeric_limits <unsigned short>::max ();
550 const float MaxUShortFloat = MaxUShort;
551+ bool usingAverageColors = false;
552
553 BoxRec box;
554 CompRegion damageRegion;
555 GLMatrix sTransform (transform);
556 GLfloat vertexData [12];
557 GLfloat vertexData2[24];
558- GLint origSrc, origDst;
559- GLushort fc[4], bc[4];
560+ GLint origSrc, origDst;
561+#ifdef USE_GLES
562+ GLint origSrcAlpha, origDstAlpha;
563+#endif
564+ GLushort fc[4], bc[4], averageFillColor[4];
565+
566+ if (optionGetUseDesktopAverageColor ())
567+ {
568+ const unsigned short *averageColor = screen->averageColor ();
569+
570+ if (averageColor)
571+ {
572+ usingAverageColors = true;
573+ borderColor = const_cast<unsigned short *>(averageColor);
574+ memcpy (averageFillColor, averageColor, 4 * sizeof (unsigned short));
575+ averageFillColor[3] = MaxUShort * 0.6;
576+
577+ if (fillColor)
578+ fillColor = averageFillColor;
579+ }
580+ }
581
582 bool blend = !optionGetDisableBlend ();
583
584@@ -107,7 +127,6 @@
585 if (blend)
586 {
587 #ifdef USE_GLES
588- GLint origSrcAlpha, origDstAlpha;
589 glGetIntegerv (GL_BLEND_SRC_RGB, &origSrc);
590 glGetIntegerv (GL_BLEND_DST_RGB, &origDst);
591 glGetIntegerv (GL_BLEND_SRC_ALPHA, &origSrcAlpha);
592@@ -118,12 +137,6 @@
593 #endif
594 }
595
596- /* Premultiply the alpha values */
597- bc[3] = blend ? ((float) borderColor[3] / MaxUShortFloat) : MaxUShortFloat;
598- bc[0] = ((float) borderColor[0] / MaxUShortFloat) * bc[3];
599- bc[1] = ((float) borderColor[1] / MaxUShortFloat) * bc[3];
600- bc[2] = ((float) borderColor[2] / MaxUShortFloat) * bc[3];
601-
602 logic.getPaintRectangle (&box);
603
604 vertexData[0] = box.x1;
605@@ -195,10 +208,48 @@
606 }
607
608 /* draw outline */
609- static const int borderWidth = 2;
610- glLineWidth (borderWidth);
611+ static const int defaultBorderWidth = 2;
612+ int borderWidth = defaultBorderWidth;
613+
614+ if (optionGetIncreaseBorderContrast() || usingAverageColors)
615+ {
616+ // Generate a lighter color based on border to create more contrast
617+ unsigned int averageColorLevel = (borderColor[0] + borderColor[1] + borderColor[2]) / 3;
618+
619+ float colorMultiplier;
620+ if (averageColorLevel > MaxUShort * 0.3)
621+ colorMultiplier = 0.7; // make it darker
622+ else
623+ colorMultiplier = 2.0; // make it lighter
624+
625+ bc[3] = borderColor[3];
626+ bc[0] = MIN(MaxUShortFloat, ((float) borderColor[0]) * colorMultiplier) * bc[3] / MaxUShortFloat;
627+ bc[1] = MIN(MaxUShortFloat, ((float) borderColor[1]) * colorMultiplier) * bc[3] / MaxUShortFloat;
628+ bc[2] = MIN(MaxUShortFloat, ((float) borderColor[2]) * colorMultiplier) * bc[3] / MaxUShortFloat;
629+
630+ if (optionGetIncreaseBorderContrast ())
631+ {
632+ borderWidth *= 2;
633+
634+ glLineWidth (borderWidth);
635+ streamingBuffer->begin (GL_LINES);
636+ streamingBuffer->addVertices (8, &vertexData2[0]);
637+ streamingBuffer->addColors (1, bc);
638+ streamingBuffer->end ();
639+ streamingBuffer->render (sTransform);
640+ } else if (usingAverageColors) {
641+ borderColor = bc;
642+ }
643+ }
644+
645+ bc[3] = blend ? borderColor[3] : MaxUShortFloat;
646+ bc[0] = borderColor[0] * bc[3] / MaxUShortFloat;
647+ bc[1] = borderColor[1] * bc[3] / MaxUShortFloat;
648+ bc[2] = borderColor[2] * bc[3] / MaxUShortFloat;
649+
650+ glLineWidth (defaultBorderWidth);
651 streamingBuffer->begin (GL_LINES);
652- streamingBuffer->addColors (1, borderColor);
653+ streamingBuffer->addColors (1, bc);
654 streamingBuffer->addVertices (8, &vertexData2[0]);
655 streamingBuffer->end ();
656 streamingBuffer->render (sTransform);
657@@ -222,21 +273,21 @@
658 damageRegion += CompRect (box.x1 - borderWidth,
659 box.y1 - borderWidth,
660 box.x2 - box.x1 + borderWidth * 2,
661- borderWidth + 1);
662+ borderWidth * 2);
663 // Right
664 damageRegion += CompRect (box.x2 - borderWidth,
665 box.y1 - borderWidth,
666- borderWidth + 1,
667+ borderWidth + borderWidth / 2,
668 box.y2 - box.y1 + borderWidth * 2);
669 // Bottom
670 damageRegion += CompRect (box.x1 - borderWidth,
671 box.y2 - borderWidth,
672 box.x2 - box.x1 + borderWidth * 2,
673- borderWidth + 1);
674+ borderWidth * 2);
675 // Left
676 damageRegion += CompRect (box.x1 - borderWidth,
677 box.y1 - borderWidth,
678- borderWidth + 1,
679+ borderWidth + borderWidth / 2,
680 box.y2 - box.y1 + borderWidth * 2);
681 }
682 else
683
684=== modified file 'src/atoms.cpp'
685--- src/atoms.cpp 2015-02-17 14:54:10 +0000
686+++ src/atoms.cpp 2017-07-03 15:16:04 +0000
687@@ -155,6 +155,8 @@
688
689 Atom startupId;
690
691+ Atom gnomeRepresentativeColors;
692+
693 void init (Display *dpy)
694 {
695 supported = XInternAtom (dpy, "_NET_SUPPORTED", 0);
696@@ -325,5 +327,7 @@
697 atomPair = XInternAtom (dpy, "ATOM_PAIR", 0);
698
699 startupId = XInternAtom (dpy, "_NET_STARTUP_ID", 0);
700+
701+ gnomeRepresentativeColors = XInternAtom (dpy, "_GNOME_BACKGROUND_REPRESENTATIVE_COLORS", 0);
702 }
703 };
704
705=== modified file 'src/event.cpp'
706--- src/event.cpp 2016-05-17 02:52:07 +0000
707+++ src/event.cpp 2017-07-03 15:16:04 +0000
708@@ -1821,6 +1821,11 @@
709 if (w)
710 w->priv->updateStartupId ();
711 }
712+ else if (event->xproperty.atom == Atoms::gnomeRepresentativeColors)
713+ {
714+ if (event->xproperty.window == privateScreen.rootWindow())
715+ privateScreen.updateAverageColor (event->xproperty.atom);
716+ }
717 else if (event->xproperty.atom == XA_WM_CLASS)
718 {
719 w = findWindow (event->xproperty.window);
720
721=== modified file 'src/privatescreen.h'
722--- src/privatescreen.h 2016-05-17 02:52:07 +0000
723+++ src/privatescreen.h 2017-07-03 15:16:04 +0000
724@@ -692,6 +692,8 @@
725
726 void updateResources ();
727
728+ void updateAverageColor (Atom atom);
729+
730 Window getActiveWindow (Window root);
731
732 void setWindowState (unsigned int state, Window id);
733@@ -777,6 +779,8 @@
734 unsigned int nDesktop;
735 unsigned int currentDesktop;
736
737+ std::vector<unsigned short> averageColor;
738+
739 CompOutput fullscreenOutput;
740 CompScreenEdge screenEdge[SCREEN_EDGE_NUM];
741
742@@ -1092,6 +1096,7 @@
743 virtual CompWindow * getTopServerWindow() const;
744 virtual CoreOptions& getCoreOptions();
745 virtual Colormap colormap() const;
746+ virtual const unsigned short * averageColor() const;
747 virtual void setCurrentDesktop (unsigned int desktop);
748 virtual Window activeWindow() const;
749 virtual bool grabWindowIsNot(Window w) const;
750@@ -1187,6 +1192,7 @@
751 virtual void _matchPropertyChanged(CompWindow *);
752 virtual void _outputChangeNotify();
753 virtual void _cursorChangeNotify(const CompString&, int);
754+ virtual void _averageColorChangeNotify(const unsigned short*);
755
756 void grabServer ();
757 void ungrabServer ();
758
759=== modified file 'src/privatescreen/tests/test-privatescreen.cpp'
760--- src/privatescreen/tests/test-privatescreen.cpp 2016-04-26 12:42:39 +0000
761+++ src/privatescreen/tests/test-privatescreen.cpp 2017-07-03 15:16:04 +0000
762@@ -82,6 +82,7 @@
763 MOCK_METHOD1(_matchPropertyChanged, void (CompWindow *));
764 MOCK_METHOD0(_outputChangeNotify, void ());
765 MOCK_METHOD2(_cursorChangeNotify, void (const CompString&, int));
766+ MOCK_METHOD1(_averageColorChangeNotify, void (const unsigned short*));
767
768 MOCK_METHOD0(outputDevs, CompOutput::vector & ());
769 MOCK_METHOD2(setWindowState, void (unsigned int state, Window id));
770@@ -199,6 +200,7 @@
771 MOCK_CONST_METHOD0(getTopServerWindow, CompWindow * ());
772 MOCK_METHOD0(getCoreOptions, CoreOptions& ());
773 MOCK_CONST_METHOD0(colormap, Colormap ());
774+ MOCK_CONST_METHOD0(averageColor, const unsigned short * ());
775 MOCK_METHOD1(setCurrentDesktop, void (unsigned int desktop));
776 MOCK_CONST_METHOD0(activeWindow, Window ());
777 MOCK_CONST_METHOD1(grabWindowIsNot, bool (Window w));
778
779=== modified file 'src/screen.cpp'
780--- src/screen.cpp 2016-07-28 13:43:06 +0000
781+++ src/screen.cpp 2017-07-03 15:16:04 +0000
782@@ -1427,6 +1427,113 @@
783 screen->cursorChangeNotify (cursorTheme, cursorSize);
784 }
785
786+void
787+PrivateScreen::updateAverageColor (Atom atom)
788+{
789+ Atom actual_type;
790+ int result, format;
791+ unsigned long n, left;
792+ unsigned char *data;
793+
794+ auto previousAverageColor = averageColor;
795+ averageColor.clear ();
796+
797+ result = XGetWindowProperty (dpy, root,
798+ atom, 0L, 65536, False,
799+ XA_STRING, &actual_type, &format,
800+ &n, &left, &data);
801+
802+ if (result != Success || !data || actual_type != XA_STRING)
803+ {
804+ if (previousAverageColor != averageColor)
805+ screen->averageColorChangeNotify (averageColor.data ());
806+
807+ XFree (data);
808+ return;
809+ }
810+
811+ CompString colors (reinterpret_cast<char *> (data));
812+ bool found_valid;
813+ double r, g, b, a;
814+ found_valid = false;
815+ r = g = b = 0.0;
816+ a = 1.0;
817+ const CompString rgba_regex = R"((rgba?))"
818+ R"(\s*\(\s*([0-9]{1,3})\s*,)"
819+ R"(\s*([0-9]{1,3})\s*,)"
820+ R"(\s*([0-9]{1,3})\s*)"
821+ R"((,\s*((0*(\.[0-9]+)|1(\.0*)?)?)\s*)?\))";
822+
823+ std::vector<CompString> matches = compGetRegexMatches (rgba_regex, colors);
824+
825+ if (matches.size () > 4)
826+ {
827+ try
828+ {
829+ found_valid = true;
830+ r = std::stoi (matches[2]) / 255.0;
831+ g = std::stoi (matches[3]) / 255.0;
832+ b = std::stoi (matches[4]) / 255.0;
833+
834+ if (matches[1] == "rgba")
835+ {
836+ if (matches.size () > 6 && !matches[6].empty ())
837+ a = std::stod (matches[6][0] == '.' ? '0'+matches[6] : matches[6]);
838+ else
839+ found_valid = false;
840+ }
841+ } catch (std::exception const& except) {
842+ found_valid = false;
843+ compLogMessage ("core", CompLogLevelWarn, "%s: failed to parse '%s' color string",
844+ except.what (), colors.c_str ());
845+ }
846+ } else {
847+ size_t color_len = (colors.length () - 1) / 3;
848+
849+ if (color_len > 0 && color_len <= 4)
850+ {
851+ CompString hex_regex = "#([[:xdigit:]]{" + std::to_string(color_len) + "})" +
852+ "([[:xdigit:]]{" + std::to_string(color_len) + "})" +
853+ "([[:xdigit:]]{" + std::to_string(color_len) + "})" +
854+ "([[:xdigit:]]{" + std::to_string(color_len) + "})?$";
855+ std::vector<CompString> matches = compGetRegexMatches (hex_regex, colors);
856+ if (matches.size () == 5)
857+ {
858+ try
859+ {
860+ double max_value = static_cast<float> ((1 << (4 * color_len)) - 1);
861+ found_valid = true;
862+ r = std::stoi (matches[1], 0, 16) / max_value;
863+ g = std::stoi (matches[2], 0, 16) / max_value;
864+ b = std::stoi (matches[3], 0, 16) / max_value;
865+
866+ if (!matches[4].empty ())
867+ a = std::stoi (matches[4], 0, 16) / max_value;
868+ } catch (std::exception const& except) {
869+ found_valid = false;
870+ compLogMessage ("core", CompLogLevelWarn, "%s: failed to parse '%s' color string",
871+ except.what (), colors.c_str ());
872+ }
873+ }
874+ }
875+ }
876+
877+ if (found_valid)
878+ {
879+ const double MaxUShort = std::numeric_limits<unsigned short>::max ();
880+ averageColor.resize (4);
881+ averageColor[0] = MAX (0, MIN (r * MaxUShort, MaxUShort));
882+ averageColor[1] = MAX (0, MIN (g * MaxUShort, MaxUShort));
883+ averageColor[2] = MAX (0, MIN (b * MaxUShort, MaxUShort));
884+ averageColor[3] = MAX (0, MIN (a * MaxUShort, MaxUShort));
885+ }
886+
887+ XFree (data);
888+
889+ if (previousAverageColor != averageColor)
890+ screen->averageColorChangeNotify (averageColor.data ());
891+}
892+
893 bool
894 CompScreen::fileToImage (CompString &name,
895 CompSize &size,
896@@ -3153,7 +3260,7 @@
897 }
898
899 if ((type & cps::GrabType::KEYBOARD) &&
900- !eventManager.topGrab (cps::GrabType::KEYBOARD))
901+ !eventManager.topGrab (cps::GrabType::KEYBOARD))
902 {
903 status = XGrabKeyboard (dpy,
904 eventManager.getGrabWindow (), true,
905@@ -3171,7 +3278,7 @@
906 }
907 else
908 {
909- XUngrabPointer (dpy, CurrentTime);
910+ XUngrabPointer (dpy, CurrentTime);
911 }
912 }
913
914@@ -3242,7 +3349,7 @@
915 }
916 else
917 {
918- XUngrabPointer (privateScreen.dpy, CurrentTime);
919+ XUngrabPointer (privateScreen.dpy, CurrentTime);
920 }
921 }
922
923@@ -4226,10 +4333,10 @@
924 PrivateScreen::updateCursors (const CompString& theme, int size)
925 {
926 if (size > 0)
927- XcursorSetDefaultSize (dpy, size);
928+ XcursorSetDefaultSize (dpy, size);
929
930 if (!theme.empty())
931- XcursorSetTheme (dpy, theme.c_str());
932+ XcursorSetTheme (dpy, theme.c_str());
933
934 for (auto it = begin (cursors); it != end (cursors); ++it)
935 {
936@@ -4250,6 +4357,18 @@
937 privateScreen.updateCursors (theme, size);
938 }
939
940+void
941+CompScreen::averageColorChangeNotify (const unsigned short* color)
942+{
943+ WRAPABLE_HND_FUNCTN (averageColorChangeNotify, color);
944+ _averageColorChangeNotify (color);
945+}
946+
947+void
948+CompScreenImpl::_averageColorChangeNotify (const unsigned short* color)
949+{
950+}
951+
952 /* Returns default viewport for some window geometry. If the window spans
953 * more than one viewport the most appropriate viewport is returned. How the
954 * most appropriate viewport is computed can be made optional if necessary. It
955@@ -4396,6 +4515,10 @@
956 ScreenInterface::cursorChangeNotify (const CompString& theme, int size)
957 WRAPABLE_DEF (cursorChangeNotify, theme, size)
958
959+void
960+ScreenInterface::averageColorChangeNotify (const unsigned short *color)
961+ WRAPABLE_DEF (averageColorChangeNotify, color)
962+
963 Window
964 CompScreenImpl::root ()
965 {
966@@ -4841,6 +4964,12 @@
967 return privateScreen.colormap;
968 }
969
970+const unsigned short *
971+CompScreenImpl::averageColor() const
972+{
973+ return privateScreen.averageColor.data ();
974+}
975+
976 void
977 CompScreenImpl::setCurrentDesktop (unsigned int desktop)
978 {
979@@ -5270,6 +5399,8 @@
980 XIGetClientPointer (dpy, None, &clientPointerDeviceId);
981 updateResources ();
982
983+ updateAverageColor (Atoms::gnomeRepresentativeColors);
984+
985 /* Attempt to gain SubstructureRedirectMask */
986 CompScreenImpl::checkForError (dpy);
987
988
989=== modified file 'src/string/src/string.cpp'
990--- src/string/src/string.cpp 2012-03-23 03:37:26 +0000
991+++ src/string/src/string.cpp 2017-07-03 15:16:04 +0000
992@@ -1,5 +1,6 @@
993 /*
994 * Copyright © 2008 Dennis Kasprzyk
995+ * Copyright © 2017 Canonical Ltd.
996 *
997 * Permission to use, copy, modify, distribute, and sell this software
998 * and its documentation for any purpose is hereby granted without
999@@ -21,12 +22,20 @@
1000 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1001 *
1002 * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
1003+ * Marco Trevisan <marco.trevisan@canonical.com>
1004 */
1005
1006 #include <cstring>
1007 #include <cstdarg>
1008 #include <cstdio>
1009
1010+#if defined(__GNUC__) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9)))
1011+#include <regex.h>
1012+#else
1013+#include <regex>
1014+#define HAVE_CPP_REGEX
1015+#endif
1016+
1017 #include <core/string.h>
1018
1019 CompString compPrintf (const char *format, ...)
1020@@ -86,3 +95,55 @@
1021 delete [] str;
1022 return rv;
1023 }
1024+
1025+CompStringVector
1026+compGetRegexMatches(const CompString& regexStr,
1027+ const CompString& string)
1028+{
1029+
1030+ CompStringVector matches;
1031+
1032+#ifdef HAVE_CPP_REGEX
1033+
1034+ std::smatch subMatches;
1035+ std::regex regex(regexStr);
1036+
1037+ if (std::regex_match(string, subMatches, regex))
1038+ {
1039+ for (const auto& subMatch : subMatches)
1040+ matches.push_back (subMatch.str ());
1041+ }
1042+
1043+#else
1044+
1045+ regex_t regex;
1046+ int ret;
1047+ ret = regcomp (&regex, regexStr.c_str (), REG_EXTENDED);
1048+
1049+ if (ret != 0)
1050+ return matches;
1051+
1052+ std::vector<regmatch_t> subMatches (regex.re_nsub + 1);
1053+ ret = regexec (&regex, string.c_str (), subMatches.size (), subMatches.data (), 0);
1054+
1055+ if (ret == REG_NOMATCH)
1056+ return matches;
1057+
1058+ for (const auto& sub_match : subMatches)
1059+ {
1060+ if (sub_match.rm_so >= 0)
1061+ {
1062+ size_t sub_len = sub_match.rm_eo - sub_match.rm_so;
1063+ matches.push_back (string.substr (sub_match.rm_so, sub_len));
1064+ } else {
1065+ /* We keep this empty so the clients might access to all the subs */
1066+ matches.push_back (CompString ());
1067+ }
1068+ }
1069+
1070+ regfree (&regex);
1071+
1072+#endif
1073+
1074+ return matches;
1075+}

Subscribers

People subscribed via source and target branches