Newer
Older
David Reveman
committed
/*
* Copyright © 2006 Novell, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: David Reveman <davidr@novell.com>
David Reveman
committed
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <math.h>
David Reveman
committed
#include <decoration.h>
#include <X11/Xregion.h>
int
decor_version (void)
{
return DECOR_INTERFACE_VERSION;
}
David Reveman
committed
/*
decoration property
-------------------
data[0] = version
data[1] = decoration type
David Reveman
committed
data[2] = number of decorations specified in property
WINDOW_DECORATION_TYPE_WINDOW property
--------------------------------------
data[3] = input left
data[4] = input right
data[5] = input top
data[6] = input bottom
data[7] = input left when maximized
data[8] = input right when maximized
data[9] = input top when maximized
data[10] = input bottom when maximized
data[11] = min width
data[12] = min height
fields 13 to 15 are only used by the default
decorations on the root window
data[13] = frame state
data[14] = frame type
data[15] = frame actions
WINDOW_DECORATION_TYPE_PIXMAP property
--------------------------------------
David Reveman
committed
data[3] = pixmap
David Reveman
committed
extents
frame input is used for creating the input area of
the frame window which the client will be
reparented into, border is used for positioning
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
data[4] = frame left
data[5] = frame right
data[6] = frame top
data[7] = frame bottom
data[8] = input left
data[9] = input right
data[10] = input top
data[11] = input bottom
data[12] = frame left when maximized
data[13] = frame right when maximized
data[14] = frame top when maximized
data[15] = frame bottom when maximized
data[16] = border left when maximized
data[17] = border right when maximized
data[18] = border top when maximized
data[19] = border bottom when maximized
data[20] = min width
data[21] = min height
fields 22 to 24 are only used by the default
decorations on the root window
data[22] = frame state
data[23] = frame type
data[24] = frame actions
data[25] = num quads
David Reveman
committed
flags
1st to 4nd bit p1 gravity, 5rd to 8th bit p2 gravity,
9rd and 10th bit alignment, 11rd and 12th bit clamp,
13th bit XX, 14th bit XY, 15th bit YX, 16th bit YY.
data[26 + n * 9 + 1] = flags
data[26 + n * 9 + 2] = p1 x
data[26 + n * 9 + 3] = p1 y
data[26 + n * 9 + 4] = p2 x
data[26 + n * 9 + 5] = p2 y
data[26 + n * 9 + 6] = widthMax
data[26 + n * 9 + 7] = heightMax
data[26 + n * 9 + 8] = x0
data[26 + n * 9 + 9] = y0
David Reveman
committed
*/
long *
decor_alloc_property (unsigned int n,
unsigned int type)
{
Daniel van Vugt
committed
unsigned int propSize = 0;
long *data;
if (type == WINDOW_DECORATION_TYPE_WINDOW)
propSize = WINDOW_PROP_SIZE;
else if (type == WINDOW_DECORATION_TYPE_PIXMAP)
propSize = BASE_PROP_SIZE + N_QUADS_MAX * QUAD_PROP_SIZE;
propSize *= n;
propSize += PROP_HEADER_SIZE;
data = calloc (propSize, sizeof (long));
data[0] = DECOR_INTERFACE_VERSION;
data[1] = type;
data[2] = n;
return data;
}
David Reveman
committed
void
decor_quads_to_property (long *data,
unsigned int n,
David Reveman
committed
Pixmap pixmap,
decor_extents_t *frame,
decor_extents_t *border,
decor_extents_t *max_frame,
decor_extents_t *max_border,
David Reveman
committed
int min_width,
int min_height,
decor_quad_t *quad,
int nQuad,
unsigned int frame_type,
unsigned int frame_state,
unsigned int frame_actions)
David Reveman
committed
{
/* FIXME: Allocating for N_QUAD_MAX is slightly inefficient, but there
* isn't really a better way to do this at the moment */
data += PROP_HEADER_SIZE + n * (BASE_PROP_SIZE + QUAD_PROP_SIZE * N_QUADS_MAX);
David Reveman
committed
memcpy (data++, &pixmap, sizeof (Pixmap));
*data++ = frame->left;
*data++ = frame->right;
*data++ = frame->top;
*data++ = frame->bottom;
*data++ = border->left;
*data++ = border->right;
*data++ = border->top;
*data++ = border->bottom;
*data++ = max_frame->left;
*data++ = max_frame->right;
*data++ = max_frame->top;
*data++ = max_frame->bottom;
*data++ = max_border->left;
*data++ = max_border->right;
*data++ = max_border->top;
*data++ = max_border->bottom;
David Reveman
committed
*data++ = min_width;
*data++ = min_height;
*data++ = frame_type;
*data++ = frame_actions;
*data++ = nQuad;
David Reveman
committed
while (nQuad--)
{
*data++ =
(quad->p1.gravity << 0) |
(quad->p2.gravity << 4) |
(quad->align << 8) |
(quad->clamp << 10) |
(quad->stretch << 12) |
David Reveman
committed
(quad->m.xx ? XX_MASK : 0) |
(quad->m.xy ? XY_MASK : 0) |
(quad->m.yx ? YX_MASK : 0) |
(quad->m.yy ? YY_MASK : 0);
*data++ = quad->p1.x;
*data++ = quad->p1.y;
*data++ = quad->p2.x;
*data++ = quad->p2.y;
*data++ = quad->max_width;
*data++ = quad->max_height;
*data++ = quad->m.x0;
*data++ = quad->m.y0;
David Reveman
committed
}
}
void
decor_gen_window_property (long *data,
unsigned int n,
decor_extents_t *input,
decor_extents_t *max_input,
int min_width,
int min_height,
unsigned int frame_type,
unsigned int frame_state,
unsigned int frame_actions)
data += PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE;
*data++ = input->left;
*data++ = input->right;
*data++ = input->top;
*data++ = input->bottom;
*data++ = max_input->left;
*data++ = max_input->right;
*data++ = max_input->top;
*data++ = max_input->bottom;
*data++ = min_width;
*data++ = min_height;
*data++ = frame_type;
*data++ = frame_actions;
int
decor_property_get_version (long *data)
{
return (int) *data;
}
int
decor_property_get_type (long *data)
{
return (int) data[1];
}
int
decor_property_get_num (long *data)
{
return (int) data[2];
}
int
decor_pixmap_property_to_quads (long *data,
unsigned int nOffset,
decor_extents_t *frame,
decor_extents_t *border,
decor_extents_t *max_frame,
decor_extents_t *max_border,
int *min_width,
int *min_height,
unsigned int *frame_type,
unsigned int *frame_actions,
decor_quad_t *quad)
{
int i, n, flags;
if (size < PROP_HEADER_SIZE + nOffset * (BASE_PROP_SIZE + QUAD_PROP_SIZE + N_QUADS_MAX))
return 0;
if (decor_property_get_version (data) != decor_version ())
return 0;
if (decor_property_get_type (data) != WINDOW_DECORATION_TYPE_PIXMAP)
return 0;
data += PROP_HEADER_SIZE + nOffset * (BASE_PROP_SIZE + N_QUADS_MAX * QUAD_PROP_SIZE);
memcpy (pixmap, data++, sizeof (Pixmap));
frame->left = *data++;
frame->right = *data++;
frame->top = *data++;
frame->bottom = *data++;
border->left = *data++;
border->right = *data++;
border->top = *data++;
border->bottom = *data++;
max_frame->left = *data++;
max_frame->right = *data++;
max_frame->top = *data++;
max_frame->bottom = *data++;
max_border->left = *data++;
max_border->right = *data++;
max_border->top = *data++;
max_border->bottom = *data++;
*min_width = *data++;
*min_height = *data++;
*frame_type = *data++;
*frame_state = *data++;
*frame_actions = *data++;
n = *data++;
{
flags = *data++;
quad->p1.gravity = (flags >> 0) & 0xf;
quad->p2.gravity = (flags >> 4) & 0xf;
quad->align = (flags >> 8) & 0x3;
quad->clamp = (flags >> 10) & 0x3;
quad->stretch = (flags >> 12) & 0x3;
quad->m.xx = (flags & XX_MASK) ? 1.0f : 0.0f;
quad->m.xy = (flags & XY_MASK) ? 1.0f : 0.0f;
quad->m.yx = (flags & YX_MASK) ? 1.0f : 0.0f;
quad->m.yy = (flags & YY_MASK) ? 1.0f : 0.0f;
quad->p1.x = *data++;
quad->p1.y = *data++;
quad->p2.x = *data++;
quad->p2.y = *data++;
quad->max_width = *data++;
quad->max_height = *data++;
quad->m.x0 = *data++;
quad->m.y0 = *data++;
}
return n;
}
Daniel van Vugt
committed
static int
decor_point_cmp (const decor_point_t *a, const decor_point_t *b)
{
/* Use binary | to avoid branch prediction slow-downs */
return (a->x - b->x) | (a->y - b->y) | (a->gravity - b->gravity);
}
int
decor_shadow_options_cmp (const decor_shadow_options_t *a,
const decor_shadow_options_t *b)
{
return (a->shadow_radius != b->shadow_radius) ||
(a->shadow_opacity != b->shadow_opacity) ||
(a->shadow_offset_x != b->shadow_offset_x) ||
(a->shadow_offset_y != b->shadow_offset_y) ||
memcmp (a->shadow_color, b->shadow_color, sizeof (unsigned short) * 3);
}
Daniel van Vugt
committed
static int
decor_matrix_cmp (const decor_matrix_t *a, const decor_matrix_t *b)
{
return (a->xx != b->xx) ||
(a->yx != b->yx) ||
(a->xy != b->xy) ||
(a->yy != b->yy) ||
(a->x0 != b->x0) ||
(a->y0 != b->y0);
Daniel van Vugt
committed
}
static int
decor_quad_cmp (const decor_quad_t *a, const decor_quad_t *b)
{
return decor_point_cmp (&a->p1, &b->p1) ||
decor_point_cmp (&a->p2, &b->p2) ||
decor_matrix_cmp (&a->m, &b->m) ||
(
(a->max_width - b->max_width) |
(a->max_height - b->max_height) |
(a->align - b->align) |
(a->clamp - b->clamp) |
(a->stretch - b->stretch)
);
}
Sam Spilsbury
committed
int
Daniel van Vugt
committed
decor_extents_cmp (const decor_extents_t *a, const decor_extents_t *b)
{
/* Use binary | to avoid branch prediction slow-downs */
return (a->left - b->left) |
(a->right - b->right) |
(a->top - b->top) |
(a->bottom - b->bottom);
}
/* Returns n for a match, returns -1 for no match */
int
decor_match_pixmap (long *data,
int size,
Pixmap *pixmap,
decor_extents_t *frame,
decor_extents_t *border,
decor_extents_t *max_frame,
decor_extents_t *max_border,
int min_width,
int min_height,
unsigned int frame_type,
unsigned int frame_state,
unsigned int frame_actions,
decor_quad_t *quad,
unsigned int n_quad)
{
int n = decor_property_get_num (data);
unsigned int i = 0;
{
Pixmap cPixmap;
decor_extents_t cFrame, cBorder, cMax_frame, cMax_border;
int cMin_width, cMin_height;
Daniel van Vugt
committed
int q;
unsigned int cFrame_type, cFrame_state, cFrame_actions, cNQuad;
decor_quad_t cQuad[N_QUADS_MAX];
cNQuad = decor_pixmap_property_to_quads (data, i, size, &cPixmap, &cFrame, &cBorder, &cMax_frame,
&cMax_border, &cMin_width, &cMin_height, &cFrame_type,
&cFrame_state, &cFrame_actions, cQuad);
if (cPixmap != *pixmap)
continue;
Daniel van Vugt
committed
if (decor_extents_cmp (&cFrame, frame) ||
decor_extents_cmp (&cBorder, border) ||
decor_extents_cmp (&cMax_frame, max_frame) ||
decor_extents_cmp (&cMax_border, max_border))
continue;
if (cFrame_type != frame_type ||
cFrame_state != frame_state ||
cFrame_actions != frame_actions ||
cMin_width != min_width ||
cMin_height != min_height)
continue;
if (cNQuad != n_quad)
continue;
Daniel van Vugt
committed
q = 0;
while (q < n_quad && !decor_quad_cmp (&cQuad[q], &quad[q]))
Daniel van Vugt
committed
if (q < n_quad)
continue;
return n;
}
return -1;
}
int
decor_window_property (long *data,
unsigned int n,
int size,
decor_extents_t *input,
decor_extents_t *max_input,
int *min_width,
int *min_height,
unsigned int *frame_type,
unsigned int *frame_state,
unsigned int *frame_actions)
{
if (decor_property_get_version (data) != decor_version ())
return 0;
if (decor_property_get_type (data) != WINDOW_DECORATION_TYPE_WINDOW)
return 0;
if (size < PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE)
return 0;
data += PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE;
input->left = *data++;
input->right = *data++;
input->top = *data++;
input->bottom = *data++;
max_input->left = *data++;
max_input->right = *data++;
max_input->top = *data++;
max_input->bottom = *data++;
*min_width = *data++;
*min_height = *data++;
*frame_type = *data++;
*frame_state = *data++;
*frame_actions = *data++;
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
static int
add_blur_boxes (long *data,
BoxPtr box,
int n_box,
int width,
int height,
int gravity,
int offset)
{
int x1, y1, x2, y2;
int more_gravity;
int n = n_box;
while (n--)
{
x1 = box->x1;
y1 = box->y1;
x2 = box->x2;
y2 = box->y2;
if (gravity & (GRAVITY_NORTH | GRAVITY_SOUTH))
{
if (x1 > offset)
{
more_gravity = GRAVITY_EAST;
x1 -= width;
}
else
{
more_gravity = GRAVITY_WEST;
}
}
else
{
if (y1 > offset)
{
more_gravity = GRAVITY_SOUTH;
y1 -= height;
}
else
{
more_gravity = GRAVITY_NORTH;
}
}
*data++ = gravity | more_gravity;
*data++ = x1;
*data++ = y1;
if (gravity & (GRAVITY_NORTH | GRAVITY_SOUTH))
{
if (x2 > offset)
{
more_gravity = GRAVITY_EAST;
x2 -= width;
}
else
{
more_gravity = GRAVITY_WEST;
}
}
else
{
if (y2 > offset)
{
more_gravity = GRAVITY_SOUTH;
y2 -= height;
}
else
{
more_gravity = GRAVITY_NORTH;
}
}
*data++ = gravity | more_gravity;
*data++ = x2;
*data++ = y2;
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
}
return n_box * 6;
}
void
decor_region_to_blur_property (long *data,
int threshold,
int filter,
int width,
int height,
Region top_region,
int top_offset,
Region bottom_region,
int bottom_offset,
Region left_region,
int left_offset,
Region right_region,
int right_offset)
{
*data++ = threshold;
*data++ = filter;
if (top_region)
data += add_blur_boxes (data,
top_region->rects,
top_region->numRects,
width, height,
GRAVITY_NORTH,
top_offset);
if (bottom_region)
data += add_blur_boxes (data,
bottom_region->rects,
bottom_region->numRects,
width, height,
GRAVITY_SOUTH,
bottom_offset);
if (left_region)
data += add_blur_boxes (data,
left_region->rects,
left_region->numRects,
width, height,
GRAVITY_WEST,
left_offset);
if (right_region)
data += add_blur_boxes (data,
right_region->rects,
right_region->numRects,
width, height,
GRAVITY_EAST,
right_offset);
}
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
void
decor_apply_gravity (int gravity,
int x,
int y,
int width,
int height,
int *return_x,
int *return_y)
{
if (gravity & GRAVITY_EAST)
{
x += width;
*return_x = MAX (0, x);
}
else if (gravity & GRAVITY_WEST)
{
*return_x = MIN (width, x);
}
else
{
x += width / 2;
x = MAX (0, x);
x = MIN (width, x);
*return_x = x;
}
if (gravity & GRAVITY_SOUTH)
{
y += height;
*return_y = MAX (0, y);
}
else if (gravity & GRAVITY_NORTH)
{
*return_y = MIN (height, y);
}
else
{
y += height / 2;
y = MAX (0, y);
y = MIN (height, y);
*return_y = y;
}
}
int
decor_set_vert_quad_row (decor_quad_t *q,
int top,
int top_corner,
int bottom,
int bottom_corner,
int left,
int right,
int gravity,
int height,
int splitY,
int splitGravity,
double x0,
double y0,
int rotation)
{
int nQuad = 0;
q->p1.x = left;
q->p1.y = -top;
q->p1.gravity = gravity | GRAVITY_NORTH;
q->p2.x = right;
q->p2.y = splitY;
q->p2.gravity = gravity | splitGravity;
q->max_width = SHRT_MAX;
q->max_height = top + top_corner;
q->align = ALIGN_TOP;
q->clamp = CLAMP_VERT;
q->m.x0 = x0;
q->m.y0 = y0;
if (rotation)
{
q->m.xx = 0.0;
q->m.xy = 1.0;
q->m.yx = 1.0;
q->m.yy = 0.0;
}
else
{
q->m.xx = 1.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 1.0;
}
q->p1.x = left;
q->p1.y = top_corner;
q->p1.gravity = gravity | GRAVITY_NORTH;
q->p2.x = right;
q->p2.y = -bottom_corner;
q->p2.gravity = gravity | GRAVITY_SOUTH;
q->max_width = SHRT_MAX;
q->max_height = SHRT_MAX;
q->align = 0;
q->clamp = CLAMP_VERT;
if (rotation)
{
q->m.xx = 0.0;
q->m.xy = 0.0;
q->m.yx = 1.0;
q->m.yy = 0.0;
q->m.x0 = x0 + top + top_corner;
q->m.y0 = y0;
}
else
{
q->m.xx = 1.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 0.0;
q->m.x0 = x0;
q->m.y0 = y0 + top + top_corner;
}
q->p1.x = left;
q->p1.y = splitY;
q->p1.gravity = gravity | splitGravity;
q->p2.x = right;
q->p2.y = bottom;
q->p2.gravity = gravity | GRAVITY_SOUTH;
q->max_width = SHRT_MAX;
q->max_height = bottom_corner + bottom;
q->align = ALIGN_BOTTOM;
q->clamp = CLAMP_VERT;
if (rotation)
{
q->m.xx = 0.0;
q->m.xy = 1.0;
q->m.yx = 1.0;
q->m.yy = 0.0;
q->m.x0 = x0 + height;
q->m.y0 = y0;
}
else
{
q->m.xx = 1.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 1.0;
q->m.x0 = x0;
q->m.y0 = y0 + height;
}
return nQuad;
}
David Reveman
committed
int
decor_set_horz_quad_line (decor_quad_t *q,
int left,
int left_corner,
int right,
int right_corner,
int top,
int bottom,
int gravity,
int width,
int splitX,
int splitGravity,
David Reveman
committed
double x0,
double y0)
{
David Reveman
committed
q->p1.x = -left;
q->p1.y = top;
q->p1.gravity = gravity | GRAVITY_WEST;
David Reveman
committed
q->p2.y = bottom;
q->p2.gravity = gravity | splitGravity;
David Reveman
committed
q->max_width = left + left_corner;
q->max_height = SHRT_MAX;
q->align = ALIGN_LEFT;
q->clamp = 0;
David Reveman
committed
q->m.xx = 1.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 1.0;
q->m.x0 = x0;
q->m.y0 = y0;
David Reveman
committed
q->p1.x = left_corner;
q->p1.y = top;
q->p1.gravity = gravity | GRAVITY_WEST;
q->p2.x = -right_corner;
q->p2.y = bottom;
q->p2.gravity = gravity | GRAVITY_EAST;
q->max_width = SHRT_MAX;
q->max_height = SHRT_MAX;
q->align = 0;
q->clamp = 0;
David Reveman
committed
q->m.xx = 0.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 1.0;
q->m.x0 = x0 + left + left_corner;
q->m.y0 = y0;
David Reveman
committed
David Reveman
committed
q->p1.y = top;
q->p1.gravity = gravity | splitGravity;
David Reveman
committed
q->p2.x = right;
q->p2.y = bottom;
q->p2.gravity = gravity | GRAVITY_EAST;
q->max_width = right_corner + right;
q->max_height = SHRT_MAX;
q->align = ALIGN_RIGHT;
q->clamp = 0;
David Reveman
committed
q->m.xx = 1.0;
q->m.xy = 0.0;
q->m.yx = 0.0;
q->m.yy = 1.0;
q->m.x0 = x0 + width;
q->m.y0 = y0;
David Reveman
committed
return nQuad;
}
int
decor_set_lSrS_window_quads (decor_quad_t *q,
decor_context_t *c,
decor_layout_t *l)
David Reveman
committed
{
int lh, rh, splitY, n, nQuad = 0;
David Reveman
committed
splitY = (c->top_corner_space - c->bottom_corner_space) / 2;
David Reveman
committed
if (l->rotation)
{
lh = l->left.x2 - l->left.x1;
rh = l->right.x2 - l->right.x1;
}
else
{
lh = l->left.y2 - l->left.y1;
rh = l->right.y2 - l->right.y1;
}
David Reveman
committed
/* left quads */
n = decor_set_vert_quad_row (q,
0,
c->top_corner_space,
0,
c->bottom_corner_space,
-c->left_space,
0,
GRAVITY_WEST,
lh,
l->left.x1,
l->left.y1,
l->rotation);
David Reveman
committed
q += n; nQuad += n;
/* right quads */
n = decor_set_vert_quad_row (q,
0,
c->top_corner_space,
0,
c->bottom_corner_space,
0,
c->right_space,
GRAVITY_EAST,
rh,
l->right.x1,
l->right.y1,
l->rotation);
David Reveman
committed
nQuad += n;
return nQuad;
}
int
decor_set_lSrStSbS_window_quads (decor_quad_t *q,
decor_context_t *c,
decor_layout_t *l)
{
int splitX, n, nQuad = 0;
splitX = (c->left_corner_space - c->right_corner_space) / 2;
/* top quads */
n = decor_set_horz_quad_line (q,
c->left_space,
c->left_corner_space,
c->right_space,
c->right_corner_space,
-c->top_space,
0,
GRAVITY_NORTH,
l->top.x2 - l->top.x1,
l->top.x1,
l->top.y1);
q += n; nQuad += n;
n = decor_set_lSrS_window_quads (q, c, l);