diff options
author | Eamon Walsh <ewalsh@tycho.nsa.gov> | 2009-09-17 23:08:06 -0400 |
---|---|---|
committer | Eamon Walsh <ewalsh@tycho.nsa.gov> | 2009-09-18 00:41:48 -0400 |
commit | afeb0353ceabc5e2cbb21a48159a3334e8024765 (patch) | |
tree | ca015315145e33073af2a12d70b63b1954b8e503 | |
parent | 72d98f6a2088ccacbe913d0523b08cd868f16470 (diff) |
Window decorations.
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | gtk/window-decorator/Makefile.am | 4 | ||||
-rw-r--r-- | gtk/window-decorator/gtk-window-decorator.c | 370 |
3 files changed, 354 insertions, 23 deletions
diff --git a/configure.ac b/configure.ac index 0d3cb7c..eae3e03 100644 --- a/configure.ac +++ b/configure.ac @@ -224,6 +224,9 @@ if test "x$use_dbus_glib" = "xyes"; then PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, [use_dbus_glib=yes], [use_dbus_glib=no]) fi +PKG_CHECK_MODULES(XLIBXCB, x11-xcb) +PKG_CHECK_MODULES(XCB, xcb-xselinux) + if test "$use_dbus" = yes; then AC_DEFINE(USE_DBUS_GLIB, 1, [Build dbus glib support]) fi diff --git a/gtk/window-decorator/Makefile.am b/gtk/window-decorator/Makefile.am index 762168f..d62a5bd 100644 --- a/gtk/window-decorator/Makefile.am +++ b/gtk/window-decorator/Makefile.am @@ -11,6 +11,9 @@ gtk_window_decorator_LDADD = \ @GTK_WINDOW_DECORATOR_LIBS@ \ @GCONF_LIBS@ \ @DBUS_GLIB_LIBS@ \ + @XCB_LIBS@ \ + @XLIBXCB_LIBS@ \ + -lselinux \ $(metacitylibs) gtk_window_decorator_SOURCES = \ @@ -38,6 +41,7 @@ INCLUDES = \ @METACITY_CFLAGS@ \ @GCONF_CFLAGS@ \ @DBUS_GLIB_CFLAGS@ \ + @XCB_CFLAGS@ \ -DALL_LINGUAS="\"@ALL_LINGUAS@\"" \ -DLOCALEDIR="\"@datadir@/locale"\" diff --git a/gtk/window-decorator/gtk-window-decorator.c b/gtk/window-decorator/gtk-window-decorator.c index 61e60f7..5b246ca 100644 --- a/gtk/window-decorator/gtk-window-decorator.c +++ b/gtk/window-decorator/gtk-window-decorator.c @@ -23,9 +23,17 @@ #include <config.h> #endif +#undef USE_METACITY + #include "decoration.h" +#include <selinux/selinux.h> + +#include <xcb/xcb.h> +#include <xcb/xselinux.h> + #include <X11/Xlib.h> +#include <X11/Xlib-xcb.h> #include <X11/Xatom.h> #include <X11/cursorfont.h> #include <X11/extensions/Xrender.h> @@ -249,6 +257,9 @@ static decor_extents_t _switcher_extents = { 6, 6, 6, 6 + SWITCHER_SPACE }; static int titlebar_height = 17; static int max_titlebar_height = 17; +static int seclabel_height = 20; +static int max_seclabel_height = 20; + static decor_context_t window_context = { { 0, 0, 0, 0 }, 6, 6, 4, 6, @@ -302,6 +313,7 @@ static decor_shadow_t *switcher_shadow = NULL; static GdkPixmap *decor_normal_pixmap = NULL; static GdkPixmap *decor_active_pixmap = NULL; +static GdkPixmap *security_pixmap = NULL; static Atom frame_window_atom; static Atom win_decor_atom; @@ -311,6 +323,7 @@ static Atom restack_window_atom; static Atom select_window_atom; static Atom mwm_hints_atom; static Atom switcher_fg_atom; +static Atom security_atom; static Atom toolkit_action_atom; static Atom toolkit_action_window_menu_atom; @@ -402,6 +415,10 @@ typedef struct _decor { XID prop_xid; GtkWidget *force_quit_dialog; void (*draw) (struct _decor *d); + GdkColor secfg; + decor_color_t secbg; + PangoLayout *seclayout; + gchar *seclabel; } decor_t; void (*theme_draw_window_decoration) (decor_t *d); @@ -565,6 +582,7 @@ decor_update_window_property (decor_t *d) stretch_offset); extents.top += titlebar_height; + extents.top += seclabel_height; decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap), &extents, &extents, @@ -926,8 +944,9 @@ draw_window_decoration (decor_t *d) double alpha; double x1, y1, x2, y2, x, y, h; int corners = SHADE_LEFT | SHADE_RIGHT | SHADE_TOP | SHADE_BOTTOM; - int top; + int top, title_top, label_top; int button_x; + int total_height; if (!d->pixmap) return; @@ -949,10 +968,14 @@ draw_window_decoration (decor_t *d) cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - top = _win_extents.top + titlebar_height; + total_height = titlebar_height + seclabel_height; + + top = _win_extents.top + total_height; + title_top = _win_extents.top + titlebar_height; + label_top = _win_extents.top + seclabel_height; x1 = d->context->left_space - _win_extents.left; - y1 = d->context->top_space - _win_extents.top - titlebar_height; + y1 = d->context->top_space - _win_extents.top - total_height; x2 = d->width - d->context->right_space + _win_extents.right; y2 = d->height - d->context->bottom_space + _win_extents.bottom; @@ -972,7 +995,7 @@ draw_window_decoration (decor_t *d) x1 + 0.5, y1 + 0.5, _win_extents.left - 0.5, - top - 0.5, + title_top - 0.5, 5.0, CORNER_TOPLEFT & corners, &title_color[0], 1.0, &title_color[1], alpha, SHADE_TOP | SHADE_LEFT); @@ -982,7 +1005,7 @@ draw_window_decoration (decor_t *d) y1 + 0.5, x2 - x1 - _win_extents.left - _win_extents.right, - top - 0.5, + title_top - 0.5, 5.0, 0, &title_color[0], 1.0, &title_color[1], alpha, SHADE_TOP); @@ -991,7 +1014,7 @@ draw_window_decoration (decor_t *d) x2 - _win_extents.right, y1 + 0.5, _win_extents.right - 0.5, - top - 0.5, + title_top - 0.5, 5.0, CORNER_TOPRIGHT & corners, &title_color[0], 1.0, &title_color[1], alpha, SHADE_TOP | SHADE_RIGHT); @@ -1004,7 +1027,7 @@ draw_window_decoration (decor_t *d) x1 + 0.5, y1 + 0.5, _win_extents.left - 0.5, - top - 0.5, + title_top - 0.5, 5.0, CORNER_TOPLEFT & corners, &color, 1.0, &color, alpha, SHADE_TOP | SHADE_LEFT); @@ -1014,7 +1037,7 @@ draw_window_decoration (decor_t *d) y1 + 0.5, x2 - x1 - _win_extents.left - _win_extents.right, - top - 0.5, + title_top - 0.5, 5.0, 0, &color, 1.0, &color, alpha, SHADE_TOP); @@ -1023,26 +1046,35 @@ draw_window_decoration (decor_t *d) x2 - _win_extents.right, y1 + 0.5, _win_extents.right - 0.5, - top - 0.5, + title_top - 0.5, 5.0, CORNER_TOPRIGHT & corners, &color, 1.0, &color, alpha, SHADE_TOP | SHADE_RIGHT); } fill_rounded_rectangle (cr, + x1 + _win_extents.left, + y1 + 1.0 + seclabel_height, + x2 - x1 - _win_extents.left - _win_extents.right, + seclabel_height, + 5.0, 0, + &d->secbg, 1.0, &d->secbg, 1.0, + SHADE_TOP); + + fill_rounded_rectangle (cr, x1 + 0.5, - y1 + top, + y1 + title_top, _win_extents.left - 0.5, - h, + h + seclabel_height, 5.0, 0, &color, 1.0, &color, alpha, SHADE_LEFT); fill_rounded_rectangle (cr, x2 - _win_extents.right, - y1 + top, + y1 + title_top, _win_extents.right - 0.5, - h, + h + seclabel_height, 5.0, 0, &color, 1.0, &color, alpha, SHADE_RIGHT); @@ -1093,7 +1125,7 @@ draw_window_decoration (decor_t *d) &style->fg[GTK_STATE_NORMAL], 0.7); - cairo_move_to (cr, x1 + 0.5, y1 + top - 0.5); + cairo_move_to (cr, x1 + 0.5, y1 + title_top - 0.5); cairo_rel_line_to (cr, x2 - x1 - 1.0, 0.0); cairo_stroke (cr); @@ -1282,6 +1314,19 @@ draw_window_decoration (decor_t *d) pango_cairo_show_layout (cr, d->layout); } + if (d->seclayout) + { + gdk_cairo_set_source_color_alpha (cr, + &d->secfg, + 1.0); + + cairo_move_to (cr, + d->context->left_space + 21.0, + y1 + 4.0 + titlebar_height + (seclabel_height - text_height) / 2.0); + + pango_cairo_show_layout (cr, d->seclayout); + } + if (d->icon) { cairo_translate (cr, d->context->left_space + 1, @@ -2143,6 +2188,50 @@ meta_draw_window_decoration (decor_t *d) } #endif +static void +draw_security_pixmap (decor_t *d) +{ + cairo_t *cr; + GtkStyle *style; + decor_color_t color; + double alpha; + double x1, y1, x2, y2, x, y, h; + int corners = SHADE_LEFT | SHADE_RIGHT | SHADE_TOP | SHADE_BOTTOM; + int top, title_top, label_top; + int button_x; + int total_height; + + cr = gdk_cairo_create (GDK_DRAWABLE (security_pixmap)); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_line_width (cr, 1.0); + + fill_rounded_rectangle (cr, + 0, + 0, + 1000, + max_seclabel_height * 2, + 5.0, 0, + &d->secbg, 1.0, &d->secbg, 1.0, + SHADE_TOP); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + if (d->seclayout) + { + gdk_cairo_set_source_color_alpha (cr, + &d->secfg, + 1.0); + + cairo_move_to (cr, 10, seclabel_height - text_height / 2.0); + + pango_cairo_show_layout (cr, d->seclayout); + } + + cairo_destroy (cr); +} + + #define SWITCHER_ALPHA 0xa0a0 static void @@ -2592,6 +2681,7 @@ update_default_decorations (GdkScreen *screen) d.height = d.border_layout.height; extents.top += titlebar_height; + extents.top += seclabel_height; d.draw = theme_draw_window_decoration; @@ -2744,7 +2834,7 @@ get_event_window_position (decor_t *d, { *x = pos[i][j].x + pos[i][j].xw * width; *y = pos[i][j].y + pos[i][j].yh * height + pos[i][j].yth * - (titlebar_height - 17); + (titlebar_height + seclabel_height - 17); if ((d->state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY) && (j == 0 || j == 2)) @@ -2764,7 +2854,7 @@ get_event_window_position (decor_t *d, else { *h = pos[i][j].h + pos[i][j].hh * height + pos[i][j].hth * - (titlebar_height - 17); + (titlebar_height + seclabel_height - 17); } } @@ -2783,10 +2873,10 @@ get_button_position (decor_t *d, *x = bpos[i].x + bpos[i].xw * width; *y = bpos[i].y + bpos[i].yh * height + bpos[i].yth * - (titlebar_height - 17); + (titlebar_height + seclabel_height - 17); *w = bpos[i].w + bpos[i].ww * width; *h = bpos[i].h + bpos[i].hh * height + bpos[i].hth + - (titlebar_height - 17); + (titlebar_height + seclabel_height - 17); /* hack to position multiple buttons on the right */ if (i != BUTTON_MENU) @@ -3176,6 +3266,54 @@ update_event_windows (WnckWindow *win) gdk_error_trap_pop (); } +static void +update_security_pixmap (WnckScreen *screen) +{ + WnckWindow *win; + cairo_t *cr; + long data[3]; + decor_t *d; + GdkDisplay *gdkdisplay = gdk_display_get_default (); + GdkScreen *gdkscreen = gdk_display_get_default_screen (gdkdisplay); + Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay); + Window xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (gdkscreen)); + + data[0] = GDK_PIXMAP_XID (security_pixmap); + + win = wnck_screen_get_active_window (screen); + if (win) + { + d = g_object_get_data (G_OBJECT (win), "decor"); + if (d && wnck_window_is_active (win)) + draw_security_pixmap(d); + + data[1] = d->width; + data[2] = max_seclabel_height * 2; + } + else + { + GdkColor c = { 0, 30000, 30000, 30000 }; + cr = gdk_cairo_create (GDK_DRAWABLE (security_pixmap)); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_rectangle (cr, 0, 0, 1000, max_seclabel_height * 2); + gdk_cairo_set_source_color (cr, &c); + cairo_fill (cr); + cairo_destroy (cr); + + data[1] = 250; + data[2] = max_seclabel_height * 2; + } + + gdk_error_trap_push (); + XChangeProperty (xdisplay, xroot, + security_atom, + XA_INTEGER, + 32, PropModeReplace, (guchar *) data, + 3); + gdk_display_sync (gdk_display_get_default ()); + gdk_error_trap_pop (); +} + #ifdef HAVE_WNCK_WINDOW_HAS_NAME static const char * wnck_window_get_real_name (WnckWindow *win) @@ -3185,6 +3323,82 @@ wnck_window_get_real_name (WnckWindow *win) #define wnck_window_get_name wnck_window_get_real_name #endif +static const char * +wnck_window_get_seclabel(WnckWindow *win, GdkColor *fg, decor_color_t *bg) +{ + Display *xdisplay; + xcb_connection_t *conn; + xcb_selinux_get_window_context_cookie_t cookie; + xcb_selinux_get_window_context_reply_t *reply; + xcb_generic_error_t *error; + unsigned int r1 = 0, g1 = 0, b1 = 0, r2 = 255, g2 = 255, b2 = 255; + char *color; + static security_context_t ctx; + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + conn = XGetXCBConnection(xdisplay); + + cookie = xcb_selinux_get_window_context(conn, wnck_window_get_xid(win)); + reply = xcb_selinux_get_window_context_reply(conn, cookie, &error); + if (error) { + free(error); + return NULL; + } + + free(ctx); + ctx = strdup(xcb_selinux_get_window_context_context(reply)); + + if (selinux_raw_context_to_color(ctx, &color) == 0) { + sscanf(color, "#%2x%2x%2x #%2x%2x%2x", &r1, &g1, &b1, &r2, &g2, &b2); + free(color); + } + if (fg) { + fg->pixel = 0; + fg->red = r1 * 256; + fg->green = g1 * 256; + fg->blue = b1 * 256; + } + if (bg) { + bg->r = (double)r2 / 255.0; + bg->g = (double)g2 / 255.0; + bg->b = (double)b2 / 255.0; + } + + free(reply); + return ctx; +} + +static gint +max_window_seclabel_width (WnckWindow *win) +{ + decor_t *d = g_object_get_data (G_OBJECT (win), "decor"); + const gchar *name; + gint w; + + if (!d->seclayout) + { + d->seclayout = pango_layout_new (pango_context); + if (!d->seclayout) + return 0; + + pango_layout_set_wrap (d->seclayout, PANGO_WRAP_CHAR); + } + + name = wnck_window_get_seclabel (win, NULL, NULL); + if (!name) + return 0; + + pango_layout_set_auto_dir (d->seclayout, FALSE); + pango_layout_set_width (d->seclayout, -1); + pango_layout_set_text (d->seclayout, name, strlen (name)); + pango_layout_get_pixel_size (d->seclayout, &w, NULL); + + if (d->seclabel) + pango_layout_set_text (d->seclayout, d->seclabel, strlen (d->seclabel)); + + return w + 6; +} + static gint max_window_name_width (WnckWindow *win) { @@ -3277,6 +3491,66 @@ update_window_decoration_name (WnckWindow *win) } static void +update_window_decoration_seclabel (WnckWindow *win) +{ + decor_t *d = g_object_get_data (G_OBJECT (win), "decor"); + const char *name; + glong name_length; + PangoLayoutLine *line; + + if (d->seclabel) + { + g_free (d->seclabel); + d->seclabel = NULL; + } + + name = wnck_window_get_seclabel(win, &d->secfg, &d->secbg); + if (name && (name_length = strlen (name))) + { + gint w; + + if (theme_draw_window_decoration != draw_window_decoration) + { + w = SHRT_MAX; + } + else + { + gint width; + + wnck_window_get_client_window_geometry (win, NULL, NULL, &width, + NULL); + + w = width - ICON_SPACE - 2 - d->button_width; + if (w < 1) + w = 1; + } + + pango_layout_set_auto_dir (d->seclayout, FALSE); + pango_layout_set_width (d->seclayout, w * PANGO_SCALE); + pango_layout_set_text (d->seclayout, name, name_length); + + line = pango_layout_get_line (d->seclayout, 0); + + name_length = line->length; + if (pango_layout_get_line_count (d->seclayout) > 1) + { + if (name_length < 4) + { + pango_layout_set_text (d->seclayout, NULL, 0); + return; + } + + d->seclabel = g_strndup (name, name_length); + strcpy (d->seclabel + name_length - 3, "..."); + } + else + d->seclabel = g_strndup (name, name_length); + + pango_layout_set_text (d->seclayout, d->seclabel, name_length); + } +} + +static void update_window_decoration_icon (WnckWindow *win) { decor_t *d = g_object_get_data (G_OBJECT (win), "decor"); @@ -3477,7 +3751,7 @@ update_window_decoration_size (WnckWindow *win) GdkPixmap *pixmap, *buffer_pixmap = NULL; Picture picture; gint width, height; - gint w, h, name_width; + gint w, h, name_width, seclabel_width; Display *xdisplay; xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); @@ -3485,10 +3759,14 @@ update_window_decoration_size (WnckWindow *win) wnck_window_get_client_window_geometry (win, NULL, NULL, &w, &h); name_width = max_window_name_width (win); + seclabel_width = max_window_seclabel_width (win); + if (seclabel_width > name_width) + name_width = seclabel_width; if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height)) { update_window_decoration_name (win); + update_window_decoration_seclabel (win); return FALSE; } @@ -3530,6 +3808,7 @@ update_window_decoration_size (WnckWindow *win) d->prop_xid = wnck_window_get_xid (win); update_window_decoration_name (win); + update_window_decoration_seclabel (win); queue_decor_draw (d); @@ -3835,12 +4114,24 @@ remove_frame_window (WnckWindow *win) d->name = NULL; } + if (d->seclabel) + { + g_free (d->seclabel); + d->seclabel = NULL; + } + if (d->layout) { g_object_unref (G_OBJECT (d->layout)); d->layout = NULL; } + if (d->seclayout) + { + g_object_unref (G_OBJECT (d->seclayout)); + d->seclayout = NULL; + } + if (d->icon) { cairo_pattern_destroy (d->icon); @@ -3984,6 +4275,8 @@ active_window_changed (WnckScreen *screen) WnckWindow *win; decor_t *d; + update_security_pixmap (screen); + win = wnck_screen_get_previously_active_window (screen); if (win) { @@ -4360,6 +4653,17 @@ handle_tooltip_event (WnckWindow *win, } } +static gboolean +create_security_pixmap (void) +{ + security_pixmap = create_pixmap(1000, max_seclabel_height * 2); + if (!security_pixmap) + return FALSE; + + update_security_pixmap (wnck_screen_get_default ()); + return TRUE; +} + static void common_button_event (WnckWindow *win, XEvent *xevent, @@ -5665,13 +5969,13 @@ update_shadow (void) 1, 1, _win_extents.left, _win_extents.right, - _win_extents.top + titlebar_height, + _win_extents.top + titlebar_height + seclabel_height, _win_extents.bottom, _win_extents.left - TRANSLUCENT_CORNER_SIZE, _win_extents.right - TRANSLUCENT_CORNER_SIZE, - _win_extents.top + titlebar_height - + _win_extents.top + titlebar_height + seclabel_height - TRANSLUCENT_CORNER_SIZE, _win_extents.bottom - TRANSLUCENT_CORNER_SIZE, @@ -5692,11 +5996,11 @@ update_shadow (void) 1, 1, _max_win_extents.left, _max_win_extents.right, - _max_win_extents.top + max_titlebar_height, + _max_win_extents.top + max_titlebar_height + max_seclabel_height, _max_win_extents.bottom, _max_win_extents.left - TRANSLUCENT_CORNER_SIZE, _max_win_extents.right - TRANSLUCENT_CORNER_SIZE, - _max_win_extents.top + max_titlebar_height - + _max_win_extents.top + max_titlebar_height + max_seclabel_height - TRANSLUCENT_CORNER_SIZE, _max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE, &opt, @@ -6094,6 +6398,8 @@ update_border_extents (gint text_height) _max_win_extents = _default_win_extents; max_titlebar_height = titlebar_height = (text_height < 17) ? 17 : text_height; + max_seclabel_height = seclabel_height = + (text_height < 20) ? 20 : text_height; } #ifdef USE_METACITY @@ -6911,6 +7217,8 @@ main (int argc, char *argv[]) WnckScreen *screen; gint i, j, status; gboolean replace = FALSE; + xcb_connection_t *conn; + const xcb_query_extension_reply_t *reply; #ifdef USE_METACITY char *meta_theme = NULL; @@ -7024,6 +7332,9 @@ main (int argc, char *argv[]) xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay); gdkscreen = gdk_display_get_default_screen (gdkdisplay); + conn = XGetXCBConnection(xdisplay); + xcb_prefetch_extension_data(conn, &xcb_selinux_id); + frame_window_atom = XInternAtom (xdisplay, "_NET_FRAME_WINDOW", FALSE); win_decor_atom = XInternAtom (xdisplay, DECOR_WINDOW_ATOM_NAME, FALSE); win_blur_decor_atom = XInternAtom (xdisplay, DECOR_BLUR_ATOM_NAME, FALSE); @@ -7035,6 +7346,13 @@ main (int argc, char *argv[]) switcher_fg_atom = XInternAtom (xdisplay, DECOR_SWITCH_FOREGROUND_COLOR_ATOM_NAME, FALSE); + security_atom = XInternAtom (xdisplay, "_COMPIZ_SECURITY_PIXMAP", FALSE); + + reply = xcb_get_extension_data(conn, &xcb_selinux_id); + if (!reply || !reply->present) { + fprintf(stderr, "%s: SELinux extension not present on display\n", argv[0]); + return 1; + } toolkit_action_atom = XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION", FALSE); @@ -7113,6 +7431,12 @@ main (int argc, char *argv[]) return 1; } + if (!create_security_pixmap ()) + { + fprintf (stderr, "%s, Couldn't create security pixmap\n", argv[0]); + return 1; + } + decor_set_dm_check_hint (xdisplay, gdk_screen_get_number (gdkscreen)); update_default_decorations (gdkscreen); |