Make the inactive windows less opaque; add a config option for the opacity. This patch depends on xfwm4_prop_deny_wm_opacity_change.patch. Without that patch, this patch *will* break programs which use things such as Xv overlays. With it, it *may* break them (but gxine and xine-ui in xine-lib CVS know about the new property). There is scope for tweaking here. Currently, either transient-for of or on the focus window or modal-for the focus window causes any given window to be rendered with normal opacity, as are windows which aren't placed or don't accept the input focus. A possible enhancement is to highlight the window under the pointer if it doesn't accept focus. Finally, restore_opacity (in the move/resize code) isn't needed any more. Signed-off-by: Darren Salt Index: src/settings.c =================================================================== --- src/settings.c (revision 22214) +++ src/settings.c (working copy) @@ -380,6 +380,12 @@ screen_info->params->frame_opacity = setting->data.v_int; reloadScreenSettings (screen_info, UPDATE_FRAME); } + else if (!strcmp (name, "Xfwm/InactiveOpacity")) + { + screen_info->params->inactive_opacity = setting->data.v_int; + reloadScreenSettings (screen_info, UPDATE_FRAME); + clientUpdateOpacity (screen_info, clientGetFocus ()); + } else if (!strcmp (name, "Xfwm/MoveOpacity")) { screen_info->params->move_opacity = setting->data.v_int; @@ -745,6 +751,12 @@ setIntValueFromInt ("placement_ratio", setting->data.v_int, rc); mcs_setting_free (setting); } + if (mcs_client_get_setting (screen_info->mcs_client, "Xfwm/InactiveOpacity", CHANNEL5, + &setting) == MCS_SUCCESS) + { + setIntValueFromInt ("inactive_opacity", setting->data.v_int, rc); + mcs_setting_free (setting); + } if (mcs_client_get_setting (screen_info->mcs_client, "Xfwm/MoveOpacity", CHANNEL5, &setting) == MCS_SUCCESS) { @@ -1244,6 +1256,7 @@ {"focus_new", NULL, TRUE}, {"frame_opacity", NULL, TRUE}, {"full_width_title", NULL, TRUE}, + {"inactive_opacity", NULL, TRUE}, {"keytheme", NULL, TRUE}, {"margin_bottom", NULL, FALSE}, {"margin_left", NULL, FALSE}, @@ -1390,6 +1403,8 @@ !g_ascii_strcasecmp ("true", getValue ("restore_on_move", rc)); screen_info->params->frame_opacity = abs (TOINT (getValue ("frame_opacity", rc))); + screen_info->params->inactive_opacity = + abs (TOINT (getValue ("inactive_opacity", rc))); screen_info->params->move_opacity = abs (TOINT (getValue ("move_opacity", rc))); screen_info->params->resize_opacity = Index: src/settings.h =================================================================== --- src/settings.h (revision 22214) +++ src/settings.h (working copy) @@ -149,6 +149,7 @@ int double_click_action; int easy_click; int frame_opacity; + int inactive_opacity; int move_opacity; int placement_ratio; int popup_opacity; Index: src/compositor.c =================================================================== --- src/compositor.c (revision 22214) +++ src/compositor.c (working copy) @@ -1774,7 +1774,7 @@ if (c) { cw->opacity_locked = c->opacity_locked; - cw->opacity = c->opacity; + cw->opacity = c->opacity_applied; cw->native_opacity = WIN_IS_OPAQUE(cw); } else if (getOpacity (display_info, cw->id, &cw->opacity)) @@ -2148,7 +2148,7 @@ { if (c->opacity != cw->opacity) { - c->opacity = cw->opacity; + clientSetOpacity (c, cw->opacity, 0, 0); } } } Index: src/client.c =================================================================== --- src/client.c (revision 22214) +++ src/client.c (working copy) @@ -1629,6 +1629,8 @@ /* Opacity for compositing manager */ c->opacity = NET_WM_OPAQUE; getOpacity (display_info, c->window, &c->opacity); + c->opacity_applied = c->opacity; + c->opacity_flags = 0; c->opacity_locked = getOpacityLock (display_info, c->window); @@ -2860,6 +2862,71 @@ } void +clientUpdateOpacity (ScreenInfo *screen_info, Client *focus) +{ + Client *c; + int i; + for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, ++i) + { + gboolean o = FLAG_TEST(c->type, WINDOW_TYPE_DONT_PLACE | WINDOW_TYPE_DONT_FOCUS) + || (focus == c) + || (focus && (focus->transient_for == c->window || focus->window == c->transient_for)) + || (focus && (clientIsModalFor (c, focus) || clientIsModalFor (focus, c))) +// || (focus && clientSameGroup (c, focus)) +// || (focus && clientSameGroup (c, focus) && FLAG_TEST (c->flags, CLIENT_FLAG_STATE_MODAL)) +// || (focus && clientIsTransientOrModalFor (c, focus)) +// || (focus && clientIsTransientOrModalFor (focus, c)) +// || (focus && clientIsModalFor (focus, c)) + ; + + clientSetOpacity (c, c->opacity, OPACITY_INACTIVE, o ? 0 : OPACITY_INACTIVE); + } +} + +void +clientSetOpacity (Client *c, guint opacity, guint clear, guint xor) +{ + guint applied; + + c->opacity_flags = (c->opacity_flags & ~clear) ^ xor; + + if (c->opacity_locked) + { + applied = c->opacity; + } + else + { + long long multiplier = 1, divisor = 1; + + c->opacity = applied = opacity; + + if (FLAG_TEST (c->opacity_flags, OPACITY_MOVE)) + { + multiplier *= c->screen_info->params->move_opacity; + divisor *= 100; + } + if (FLAG_TEST (c->opacity_flags, OPACITY_RESIZE)) + { + multiplier *= c->screen_info->params->resize_opacity; + divisor *= 100; + } + if (FLAG_TEST (c->opacity_flags, OPACITY_INACTIVE)) + { + multiplier *= c->screen_info->params->inactive_opacity; + divisor *= 100; + } + + applied = (guint) ((long long) applied * multiplier / divisor); + } + + if (applied != c->opacity_applied) + { + c->opacity_applied = applied; + compositorWindowSetOpacity (c->screen_info->display_info, c->frame, applied); + } +} + +void clientDecOpacity (Client * c) { ScreenInfo *screen_info; @@ -2870,8 +2937,7 @@ if ((c->opacity > OPACITY_SET_MIN) && !(c->opacity_locked )) { - c->opacity -= OPACITY_SET_STEP; - compositorWindowSetOpacity (display_info, c->frame, c->opacity); + clientSetOpacity (c, c->opacity - OPACITY_SET_STEP, 0, 0); } } @@ -2886,13 +2952,13 @@ if ((c->opacity < NET_WM_OPAQUE) && !(c->opacity_locked )) { - c->opacity += OPACITY_SET_STEP; + guint opacity = c->opacity + OPACITY_SET_STEP; - if ( c->opacity < OPACITY_SET_MIN ) + if (opacity < OPACITY_SET_MIN) { - c->opacity = NET_WM_OPAQUE ; + opacity = NET_WM_OPAQUE; } - compositorWindowSetOpacity (display_info, c->frame, c->opacity); + clientSetOpacity (c, opacity, 0, 0); } } @@ -3501,7 +3567,6 @@ Cursor cursor; int changes; gboolean g1, g2; - gboolean restore_opacity; g_return_if_fail (c != NULL); TRACE ("entering clientDoMove"); @@ -3510,7 +3575,6 @@ screen_info = c->screen_info; display_info = screen_info->display_info; - restore_opacity = FALSE; changes = CWX | CWY; passdata.c = c; @@ -3562,9 +3626,7 @@ /* Set window translucent while moving, looks nice */ if ((screen_info->params->move_opacity < 100) && !(screen_info->params->box_move) && !(c->opacity_locked)) { - compositorWindowSetOpacity (display_info, c->frame, - (guint) (c->opacity * (double) (screen_info->params->move_opacity / 100.0))); - restore_opacity = TRUE; + clientSetOpacity (c, c->opacity, OPACITY_MOVE, OPACITY_MOVE); } /* @@ -3600,10 +3662,7 @@ clientDrawOutline (c); } /* Set window opacity to its original value */ - if (restore_opacity) - { - compositorWindowSetOpacity (display_info, c->frame, c->opacity); - } + clientSetOpacity (c, c->opacity, OPACITY_MOVE, 0); wc.x = c->x; wc.y = c->y; @@ -4007,7 +4066,6 @@ MoveResizeData passdata; int w_orig, h_orig; gboolean g1, g2; - gboolean restore_opacity; g_return_if_fail (c != NULL); TRACE ("entering clientResize"); @@ -4015,7 +4073,6 @@ screen_info = c->screen_info; display_info = screen_info->display_info; - restore_opacity = FALSE; passdata.c = c; passdata.cancel_x = passdata.ox = c->width; @@ -4076,9 +4133,7 @@ /* Set window translucent while resizing, doesn't looks too nice :( */ if ((screen_info->params->resize_opacity < 100) && !(screen_info->params->box_resize) && !(c->opacity_locked)) { - compositorWindowSetOpacity (display_info, c->frame, - (guint) (c->opacity * (double) (screen_info->params->resize_opacity / 100.0))); - restore_opacity = TRUE; + clientSetOpacity (c, c->opacity, OPACITY_RESIZE, OPACITY_RESIZE); } FLAG_SET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING); @@ -4102,10 +4157,7 @@ clientDrawOutline (c); } /* Set window opacity to its original value */ - if (restore_opacity) - { - compositorWindowSetOpacity (display_info, c->frame, c->opacity); - } + clientSetOpacity (c, c->opacity, OPACITY_RESIZE, 0); if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED) && ((w_orig != c->width) || (h_orig != c->height))) Index: src/client.h =================================================================== --- src/client.h (revision 22214) +++ src/client.h (working copy) @@ -159,8 +159,11 @@ #define WINDOW_TYPE_DONT_FOCUS (WINDOW_SPLASHSCREEN | \ WINDOW_DOCK) +/* Which bits of opacity are applied */ +#define OPACITY_MOVE (1<<0) +#define OPACITY_RESIZE (1<<1) +#define OPACITY_INACTIVE (1<<2) - /* Convenient macros */ #define FLAG_TEST(flag,bits) (flag & (bits)) #define FLAG_TEST_ALL(flag,bits) ((flag & (bits)) == (bits)) @@ -269,6 +272,8 @@ ClientPixmapCache pm_cache; /* Opacity for the compositor */ guint opacity; + guint opacity_applied; + guint opacity_flags; gboolean opacity_locked; #ifdef HAVE_LIBSTARTUP_NOTIFICATION @@ -325,6 +330,8 @@ void clientToggleBelow (Client *); void clientRemoveMaximizeFlag (Client *); void clientToggleMaximized (Client *, int, gboolean); +void clientUpdateOpacity (ScreenInfo *, Client *); +void clientSetOpacity (Client *, guint opacity, guint clear, guint xor); void clientIncOpacity (Client *); void clientDecOpacity (Client *); void clientScreenResize(ScreenInfo *); Index: src/focus.c =================================================================== --- src/focus.c (revision 22214) +++ src/focus.c (working copy) @@ -187,6 +187,7 @@ clientSortRing(c); clientLower (c, c2->frame); clientSortRing(c2); + clientSetOpacity (c, c->opacity, 0, 0); } else { @@ -478,6 +479,8 @@ XChangeProperty (display_info->dpy, screen_info->xroot, display_info->atoms[NET_ACTIVE_WINDOW], XA_WINDOW, 32, PropModeReplace, (unsigned char *) data, 2); + + clientUpdateOpacity (screen_info, c); } void @@ -523,6 +526,7 @@ { pending_focus = c; XSetInputFocus (myScreenGetXDisplay (screen_info), c->window, RevertToPointerRoot, timestamp); + clientUpdateOpacity (screen_info, c); } if (FLAG_TEST(c->wm_flags, WM_FLAG_TAKEFOCUS)) { @@ -546,6 +550,7 @@ XChangeProperty (myScreenGetXDisplay (screen_info), screen_info->xroot, display_info->atoms[NET_ACTIVE_WINDOW], XA_WINDOW, 32, PropModeReplace, (unsigned char *) data, 2); XSetInputFocus (myScreenGetXDisplay (screen_info), screen_info->xfwm4_win, RevertToPointerRoot, timestamp); + clientUpdateOpacity (screen_info, c); } } Index: mcs-plugin/wmtweaks_plugin.c =================================================================== --- mcs-plugin/wmtweaks_plugin.c (revision 22214) +++ mcs-plugin/wmtweaks_plugin.c (working copy) @@ -71,6 +71,7 @@ static gboolean wrap_cycle = FALSE; static int placement_ratio = 25; +static int inactive_opacity = 100; static int move_opacity = 100; static int resize_opacity = 100; static int popup_opacity = 100; @@ -84,6 +85,7 @@ "Xfwm/EasyClick" "Xfwm/FocusHint" "Xfwm/FrameOpacity" + "Xfwm/InactiveOpacity" "Xfwm/MoveOpacity" "Xfwm/PlacementRatio" "Xfwm/PopupOpacity" @@ -549,6 +551,12 @@ gtk_widget_show (range); range = + create_int_range (mcs_plugin, _("Opacity of inactive windows"), _("Transparent"), + _("Opaque"), "Xfwm/InactiveOpacity", 10, 100, 5, &inactive_opacity); + gtk_box_pack_start (GTK_BOX (vbox), range, FALSE, TRUE, 0); + gtk_widget_show (range); + + range = create_int_range (mcs_plugin, _("Opacity of windows during move"), _("Transparent"), _("Opaque"), "Xfwm/MoveOpacity", 10, 100, 5, &move_opacity); gtk_box_pack_start (GTK_BOX (vbox), range, FALSE, TRUE, 0); @@ -703,6 +711,7 @@ init_gboolean_setting (mcs_plugin, "Xfwm/WrapCycle", &wrap_cycle); init_int_setting (mcs_plugin, "Xfwm/PlacementRatio", &placement_ratio); + init_int_setting (mcs_plugin, "Xfwm/InactiveOpacity", &inactive_opacity); init_int_setting (mcs_plugin, "Xfwm/FrameOpacity", &frame_opacity); init_int_setting (mcs_plugin, "Xfwm/MoveOpacity", &move_opacity); init_int_setting (mcs_plugin, "Xfwm/ResizeOpacity", &resize_opacity);