/*
* Copyright © 2006 Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define NEED_BUTTON_BISTATES
#define NEED_BUTTON_STATE_FLAGS
#define NEED_BUTTON_ACTIONS
#define NEED_BUTTON_FILE_NAMES
#include <emerald.h>
#include <engine.h>
//#define BASE_PROP_SIZE 12
//#define QUAD_PROP_SIZE 9
#ifndef DECOR_INTERFACE_VERSION
#define DECOR_INTERFACE_VERSION 0
#endif
#if defined (HAVE_LIBWNCK_2_19_4)
#define wnck_window_get_geometry wnck_window_get_client_window_geometry
#endif
void reload_all_settings(int sig);
GdkPixmap *pdeb;
static gboolean do_reload = FALSE;
static GdkPixmap *create_pixmap(int w, int h)
{
GdkPixmap *pixmap;
GdkVisual *visual;
GdkColormap *colormap;
visual = gdk_visual_get_best_with_depth(32);
if (!visual)
return NULL;
pixmap = gdk_pixmap_new(NULL, w, h, 32);
if (!pixmap)
return NULL;
colormap = gdk_colormap_new(visual, FALSE);
if (!colormap)
{
g_object_unref (G_OBJECT (pixmap));
return NULL;
}
gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), colormap);
g_object_unref (G_OBJECT (colormap));
return pixmap;
}
void engine_draw_frame(decor_t * d, cairo_t * cr);
gboolean load_engine(gchar * engine_name, window_settings * ws);
void load_engine_settings(GKeyFile * f, window_settings * ws);
static Atom frame_window_atom;
static Atom win_decor_atom;
static Atom win_blur_decor_atom;
static Atom wm_move_resize_atom;
static Atom restack_window_atom;
static Atom select_window_atom;
static Atom net_wm_context_help_atom;
static Atom wm_protocols_atom;
static Atom mwm_hints_atom;
static Atom switcher_fg_atom;
static Atom toolkit_action_atom;
static Atom toolkit_action_window_menu_atom;
static Atom toolkit_action_force_quit_dialog_atom;
static Atom emerald_sigusr1_atom;
static Atom utf8_string_atom;
static Time dm_sn_timestamp;
#define C(name) { 0, XC_ ## name }
#define BUTTON_NOT_VISIBLE(ddd, xxx) \
((ddd)->tobj_item_state[(xxx)] == 3 || !((ddd)->actions & button_actions[(xxx)]))
static struct _cursor
{
Cursor cursor;
unsigned int shape;
} cursor[3][3] =
{
{
C(top_left_corner), C(top_side), C(top_right_corner)},
{
C(left_side), C(left_ptr), C(right_side)},
{
C(bottom_left_corner), C(bottom_side), C(bottom_right_corner)}
}, button_cursor = C(hand2);
static char *program_name;
static GtkWidget *style_window;
static GHashTable *frame_table;
static GtkWidget *action_menu = NULL;
static gboolean action_menu_mapped = FALSE;
static gint double_click_timeout = 250;
static GtkWidget *tip_window;
static GtkWidget *tip_label;
static GTimeVal tooltip_last_popdown = { -1, -1 };
static gint tooltip_timer_tag = 0;
static GSList *draw_list = NULL;
static guint draw_idle_id = 0;
static gboolean enable_tooltips = TRUE;
static gchar *engine = NULL;
static gint get_b_offset(gint b)
{
static int boffset[B_COUNT+1];
gint i, b_t = 0;
for (i = 0; i < B_COUNT; i++)
{
boffset[i] = b_t;
if (btbistate[b_t])
{
boffset[i+1] = b_t;
i++;
}
b_t++;
}
return boffset[b];
}
static gint get_b_t_offset(gint b_t)
{
static int btoffset[B_T_COUNT];
gint i, b = 0;
for (i = 0; i < B_T_COUNT; i++)
{
btoffset[i] = b;
b++;
if (btbistate[i])
b++;
}
return btoffset[b_t];
}
window_settings *global_ws;
static gint get_real_pos(window_settings * ws, gint tobj, decor_t * d)
{
switch (d->tobj_item_state[tobj])
{
case 1:
return ((d->width + ws->left_space - ws->right_space +
d->tobj_size[0] - d->tobj_size[1] - d->tobj_size[2]) / 2 +
d->tobj_item_pos[tobj]);
case 2:
return (d->width - ws->right_space - d->tobj_size[2] +
d->tobj_item_pos[tobj]);
case 3:
return -1;
default:
return (ws->left_space + d->tobj_item_pos[tobj]);
}
}
static void update_window_extents(window_settings * ws)
{
//where 4 is v_corn_rad (8 is 2*4), 6 is...?
// 0, 0, L_EXT+4, TT_H+4, 0,0,0,0
// L_EXT+4 0, -8, T_EXT+2, 0,0,1,0
// L_EXT-4, 0, R_EXT+4, TT_H+4, 1,0,0,0
// 0, T_EXT+6, L_EXT, TT_H-6, 0,0,0,1
// L_EXT, T_EXT+2, 0, TT_H-2, 0,0,1,0
// L_EXT, T_EXT+6, R_EXT, TT_H-6, 1,0,0,1
// 0, TT_H, L_EXT+4, B_EXT+4, 0,1,0,0
// L_EXT+4, TT_H+4, -8, B_EXT, 0,1,1,0
// L_EXT-4, TT_H, R_EXT+4, B_EXT+4, 1,1,0,0
gint l_ext = ws->win_extents.left;
gint r_ext = ws->win_extents.right;
gint t_ext = ws->win_extents.top;
gint b_ext = ws->win_extents.bottom;
gint tt_h = ws->titlebar_height;
/*pos_t newpos[3][3] = {
{
{ 0, 0, 10, 21, 0, 0, 0, 0 },
{ 10, 0, -8, 6, 0, 0, 1, 0 },
{ 2, 0, 10, 21, 1, 0, 0, 0 }
}, {
{ 0, 10, 6, 11, 0, 0, 0, 1 },
{ 6, 6, 0, 15, 0, 0, 1, 0 },
{ 6, 10, 6, 11, 1, 0, 0, 1 }
}, {
{ 0, 17, 10, 10, 0, 1, 0, 0 },
{ 10, 21, -8, 6, 0, 1, 1, 0 },
{ 2, 17, 10, 10, 1, 1, 0, 0 }
}
}; */
pos_t newpos[3][3] = { {
{0, 0, l_ext + 4, tt_h + 4, 0, 0, 0, 0},
{l_ext + 4, 0, -8, t_ext + 2, 0, 0, 1, 0},
{l_ext - 4, 0, r_ext + 4, tt_h + 4, 1, 0, 0, 0}
}, {
{0, t_ext + 6, l_ext, tt_h - 6, 0, 0, 0, 1},
{l_ext, t_ext + 2, 0, tt_h - 2, 0, 0, 1, 0},
{l_ext, t_ext + 6, r_ext, tt_h - 6, 1, 0, 0, 1}
}, {
{0, tt_h, l_ext + 4, b_ext + 4, 0, 1, 0,
0},
{l_ext + 4, tt_h + 4, -8, b_ext, 0, 1, 1,
0},
{l_ext - 4, tt_h, r_ext + 4, b_ext + 4, 1,
1, 0, 0}
}
};
memcpy(ws->pos, newpos, sizeof(pos_t) * 9);
}
static int my_add_quad_row(decor_quad_t * q,
int width,
int left,
int right, int ypush, int vgrav, int x0, int y0)
{
int p1y = (vgrav == GRAVITY_NORTH) ? -ypush : 0;
int p2y = (vgrav == GRAVITY_NORTH) ? 0 : ypush - 1;
int fwidth = width - (left + right);
q->p1.x = -left;
q->p1.y = p1y; // opt: never changes
q->p1.gravity = vgrav | GRAVITY_WEST;
q->p2.x = 0;
q->p2.y = p2y;
q->p2.gravity = vgrav | GRAVITY_WEST;
q->align = 0; // opt: never changes
q->clamp = 0;
q->stretch = 0;
q->max_width = left;
q->max_height = ypush; // opt: never changes
q->m.x0 = x0;
q->m.y0 = y0; // opt: never changes
q->m.xx = 1; // opt: never changes
q->m.xy = 0;
q->m.yy = 1;
q->m.yx = 0; // opt: never changes
q++;
q->p1.x = 0;
q->p1.y = p1y;
q->p1.gravity = vgrav | GRAVITY_WEST;
q->p2.x = 0;
q->p2.y = p2y;
q->p2.gravity = vgrav | GRAVITY_EAST;
q->align = ALIGN_LEFT | ALIGN_TOP;
q->clamp = 0;
q->stretch = STRETCH_X;
q->max_width = fwidth;
q->max_height = ypush;
q->m.x0 = x0 + left;
q->m.y0 = y0;
q->m.xx = 1;
q->m.xy = 0;
q->m.yy = 1;
q->m.yx = 0;
q++;
q->p1.x = 0;
q->p1.y = p1y;
q->p1.gravity = vgrav | GRAVITY_EAST;
q->p2.x = right;
q->p2.y = p2y;
q->p2.gravity = vgrav | GRAVITY_EAST;
q->max_width = right;
q->max_height = ypush;
q->align = 0;
q->clamp = 0;
q->stretch = 0;
q->m.x0 = x0 + left + fwidth;
q->m.y0 = y0;
q->m.xx = 1;
q->m.yy = 1;
q->m.xy = 0;
q->m.yx = 0;
return 3;
}
static int my_add_quad_col(decor_quad_t * q,
int height, int xpush, int hgrav, int x0, int y0)
{
int p1x = (hgrav == GRAVITY_WEST) ? -xpush : 0;
int p2x = (hgrav == GRAVITY_WEST) ? 0 : xpush;
q->p1.x = p1x;
q->p1.y = 0;
q->p1.gravity = GRAVITY_NORTH | hgrav;
q->p2.x = p2x;
q->p2.y = 0;
q->p2.gravity = GRAVITY_SOUTH | hgrav;
q->max_width = xpush;
q->max_height = height;
q->align = 0;
q->clamp = CLAMP_VERT;
q->stretch = STRETCH_Y;
q->m.x0 = x0;
q->m.y0 = y0;
q->m.xx = 1;
q->m.xy = 0;
q->m.yy = 1;
q->m.yx = 0;
return 1;
}
static int
my_set_window_quads(decor_quad_t * q,
int width,
int height,
window_settings * ws,
gboolean max_horz, gboolean max_vert)
{
int nq;
int mnq = 0;
if (!max_vert || !max_horz || !ws->use_decoration_cropping)
{
//TOP QUAD
nq = my_add_quad_row(q, width, ws->left_space, ws->right_space,
ws->titlebar_height + ws->top_space,
GRAVITY_NORTH, 0, 0);
q += nq;
mnq += nq;
//BOTTOM QUAD
nq = my_add_quad_row(q, width, ws->left_space, ws->right_space,
ws->bottom_space, GRAVITY_SOUTH, 0,
height - ws->bottom_space);
q += nq;
mnq += nq;
nq = my_add_quad_col(q, height -
(ws->titlebar_height + ws->top_space +
ws->bottom_space), ws->left_space, GRAVITY_WEST,
0, ws->top_space + ws->titlebar_height);
q += nq;
mnq += nq;
nq = my_add_quad_col(q, height -
(ws->titlebar_height + ws->top_space +
ws->bottom_space), ws->right_space,
GRAVITY_EAST, width - ws->right_space,
ws->top_space + ws->titlebar_height);
q += nq;
mnq += nq;
}
else
{
q->p1.x = 0;
q->p1.y = -(ws->titlebar_height + ws->win_extents.top);
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
q->p2.x = 0;
q->p2.y = 0;
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
q->max_width = width - (ws->left_space + ws->right_space);
q->max_height = ws->titlebar_height + ws->win_extents.top;
q->align = ALIGN_LEFT | ALIGN_TOP;
q->clamp = 0;
q->stretch = STRETCH_X;
q->m.x0 = ws->left_space;
q->m.y0 = ws->top_space - ws->win_extents.top;
q->m.xx = 1;
q->m.xy = 0;
q->m.yy = 1;
q->m.yx = 0;
q++;
mnq++;
}
return mnq;
}
static void
decor_update_blur_property (decor_t *d,
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)
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
long *data = NULL;
int size = 0;
window_settings *ws = d->fs->ws;
if (ws->blur_type != BLUR_TYPE_ALL)
{
bottom_region = NULL;
left_region = NULL;
right_region = NULL;
if (ws->blur_type != BLUR_TYPE_TITLEBAR)
top_region = NULL;
}
if (top_region)
size += top_region->numRects;
if (bottom_region)
size += bottom_region->numRects;
if (left_region)
size += left_region->numRects;
if (right_region)
size += right_region->numRects;
if (size)
data = malloc (sizeof (long) * (2 + size * 6));
if (data)
{
decor_region_to_blur_property (data, 4, 0, width, height,
top_region, top_offset,
bottom_region, bottom_offset,
left_region, left_offset,
right_region, right_offset);
gdk_error_trap_push ();
XChangeProperty (xdisplay, d->prop_xid,
win_blur_decor_atom,
XA_INTEGER,
32, PropModeReplace, (guchar *) data,
2 + size * 6);
XSync(xdisplay, FALSE);
gdk_error_trap_pop ();
free (data);
}
else
{
gdk_error_trap_push ();
XDeleteProperty (xdisplay, d->prop_xid, win_blur_decor_atom);
XSync(xdisplay, FALSE);
gdk_error_trap_pop ();
}
}
static void decor_update_window_property(decor_t * d)
{
long data[256];
Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
window_settings *ws = d->fs->ws;
decor_extents_t maxextents;
decor_extents_t extents = ws->win_extents;
gint nQuad;
decor_quad_t quads[N_QUADS_MAX];
int w, h;
gint stretch_offset;
REGION top, bottom, left, right;
w = d->width;
h = d->height;
stretch_offset = 60;
nQuad = my_set_window_quads(quads, d->width, d->height, ws,
d->state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY,
d->state & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY);
extents.top += ws->titlebar_height;
if (ws->use_decoration_cropping)
{
maxextents.left = 0;
maxextents.right = 0;
maxextents.top = ws->titlebar_height + ws->win_extents.top;
maxextents.bottom = 0;
}
else
maxextents = extents;
decor_quads_to_property(data, GDK_PIXMAP_XID(d->pixmap),
&extents, &maxextents, 0, 0, quads, nQuad);
gdk_error_trap_push();
XChangeProperty(xdisplay, d->prop_xid,
win_decor_atom,
XA_INTEGER,
32, PropModeReplace, (guchar *) data,
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
XSync(xdisplay, FALSE);
gdk_error_trap_pop();
top.rects = &top.extents;
top.numRects = top.size = 1;
top.extents.x1 = -extents.left;
top.extents.y1 = -extents.top;
top.extents.x2 = w + extents.right;
top.extents.y2 = 0;
bottom.rects = &bottom.extents;
bottom.numRects = bottom.size = 1;
bottom.extents.x1 = -extents.left;
bottom.extents.y1 = 0;
bottom.extents.x2 = w + extents.right;
bottom.extents.y2 = extents.bottom;
left.rects = &left.extents;
left.numRects = left.size = 1;
left.extents.x1 = -extents.left;
left.extents.y1 = 0;
left.extents.x2 = 0;
left.extents.y2 = h;
right.rects = &right.extents;
right.numRects = right.size = 1;
right.extents.x1 = 0;
right.extents.y1 = 0;
right.extents.x2 = extents.right;
right.extents.y2 = h;
decor_update_blur_property (d,
w, h,
&top, stretch_offset,
&bottom, w / 2,
&left, h / 2,
&right, h / 2);
}
static int
set_switcher_quads(decor_quad_t * q, int width, int height, window_settings * ws)
{
gint n, nQuad = 0;
/* 1 top quads */
q->p1.x = -ws->left_space;
q->p1.y = -ws->top_space - SWITCHER_TOP_EXTRA;
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
q->p2.x = ws->right_space;
q->p2.y = 0;
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
q->max_width = SHRT_MAX;
q->max_height = SHRT_MAX;
q->align = 0;
q->clamp = 0;
q->stretch = 0;
q->m.xx = 1;
q->m.xy = 0;
q->m.yx = 0;
q->m.yy = 1;
q->m.x0 = 0;
q->m.y0 = 0;
q++;
nQuad++;
/* left quads */
n = decor_set_vert_quad_row(q,
0, ws->switcher_top_corner_space, 0, ws->bottom_corner_space,
-ws->left_space, 0, GRAVITY_WEST,
height - ws->top_space - ws->titlebar_height - ws->bottom_space,
(ws->switcher_top_corner_space - ws->switcher_bottom_corner_space) >> 1,
0, 0.0, ws->top_space + SWITCHER_TOP_EXTRA, FALSE);
q += n;
nQuad += n;
/* right quads */
n = decor_set_vert_quad_row(q,
0, ws->switcher_top_corner_space, 0, ws->switcher_bottom_corner_space,
0, ws->right_space, GRAVITY_EAST,
height - ws->top_space - ws->titlebar_height - ws->bottom_space,
(ws->switcher_top_corner_space - ws->switcher_bottom_corner_space) >> 1,
0, width - ws->right_space, ws->top_space + SWITCHER_TOP_EXTRA, FALSE);
q += n;
nQuad += n;
/* 1 bottom quad */
q->p1.x = -ws->left_space;
q->p1.y = 0;
q->p1.gravity = GRAVITY_SOUTH | GRAVITY_WEST;
q->p2.x = ws->right_space;
q->p2.y = ws->bottom_space + SWITCHER_SPACE;
q->p2.gravity = GRAVITY_SOUTH | GRAVITY_EAST;
q->max_width = SHRT_MAX;
q->max_height = SHRT_MAX;
q->align = 0;
q->clamp = 0;
q->stretch = 0;
q->m.xx = 1;
q->m.xy = 0;
q->m.yx = 0;
q->m.yy = 1;
q->m.x0 = 0;
q->m.y0 = height - ws->bottom_space - SWITCHER_SPACE;
nQuad++;
return nQuad;
}
static int
set_shadow_quads(decor_quad_t * q, gint width, gint height, window_settings * ws)
{
gint n, nQuad = 0;
/* top quads */
n = decor_set_horz_quad_line(q,
ws->shadow_left_space, ws->shadow_left_corner_space,
ws->shadow_right_space, ws->shadow_right_corner_space,
-ws->shadow_top_space, 0, GRAVITY_NORTH, width,
(ws->shadow_left_corner_space - ws->shadow_right_corner_space) >> 1,
0, 0.0, 0.0);
q += n;
nQuad += n;
/* left quads */
n = decor_set_vert_quad_row(q,
0, ws->shadow_top_corner_space, 0, ws->shadow_bottom_corner_space,
-ws->shadow_left_space, 0, GRAVITY_WEST,
height - ws->shadow_top_space - ws->shadow_bottom_space,
(ws->shadow_top_corner_space - ws->shadow_bottom_corner_space) >> 1,
0, 0.0, ws->shadow_top_space, FALSE);
q += n;
nQuad += n;
/* right quads */
n = decor_set_vert_quad_row(q,
0, ws->shadow_top_corner_space, 0, ws->shadow_bottom_corner_space, 0,
ws->shadow_right_space, GRAVITY_EAST,
height - ws->shadow_top_space - ws->shadow_bottom_space,
(ws->shadow_top_corner_space - ws->shadow_bottom_corner_space) >> 1,
0, width - ws->shadow_right_space, ws->shadow_top_space, FALSE);
q += n;
nQuad += n;
/* bottom quads */
n = decor_set_horz_quad_line(q,
ws->shadow_left_space, ws->shadow_left_corner_space,
ws->shadow_right_space, ws->shadow_right_corner_space, 0,
ws->shadow_bottom_space, GRAVITY_SOUTH, width,
(ws->shadow_left_corner_space - ws->shadow_right_corner_space) >> 1,
0, 0.0, ws->shadow_top_space + ws->shadow_top_corner_space +
ws->shadow_bottom_corner_space + 1.0);
nQuad += n;
return nQuad;
}
static void
gdk_cairo_set_source_color_alpha(cairo_t * cr, GdkColor * color, double alpha)
{
cairo_set_source_rgba(cr,
color->red / 65535.0,
color->green / 65535.0,
color->
|