Index: libwnck/window-action-menu.c =================================================================== --- libwnck/window-action-menu.c.orig +++ libwnck/window-action-menu.c @@ -49,6 +49,7 @@ typedef enum ABOVE, MOVE, RESIZE, + CHANGE_OPACITY, PIN, UNPIN, LEFT, @@ -69,6 +70,7 @@ struct _ActionMenuData GtkWidget *above_item; GtkWidget *move_item; GtkWidget *resize_item; + GtkWidget *opacity_item; GtkWidget *close_item; GtkWidget *workspace_separator; GtkWidget *pin_item; @@ -181,6 +183,15 @@ item_activated_callback (GtkWidget *menu case RESIZE: wnck_window_keyboard_size (amd->window); break; + case CHANGE_OPACITY: { + int opacity_value; + + opacity_value = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), + "opacity")); + + wnck_window_set_opacity (amd->window, opacity_value); + } break; case PIN: if (!viewport_mode) wnck_window_pin (amd->window); @@ -1059,6 +1070,47 @@ wnck_create_window_action_menu (WnckWind gtk_menu_shell_append (GTK_MENU_SHELL (menu), amd->workspace_item); + if (wnck_screen_net_wm_supports (wnck_window_get_screen (amd->window), + "_NET_WM_WINDOW_OPACITY")) + { + guint present_opacity; + gint j; + + amd->opacity_item = gtk_menu_item_new_with_mnemonic (_("_Opacity")); + gtk_widget_show (amd->opacity_item); + + submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (amd->opacity_item), + submenu); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), amd->opacity_item); + + present_opacity = wnck_window_get_opacity (window); + for (j = 0; j < 4; j++) + { + GtkWidget *item; + gchar *label; + guint o; + + label = g_strdup_printf ("%d%%", (j + 1) * 25); + + item = make_menu_item (amd, CHANGE_OPACITY); + + o = (j + 1) * 25; + g_object_set_data (G_OBJECT (item), "opacity", GINT_TO_POINTER (o)); + + if (o == present_opacity) + gtk_widget_set_sensitive (item, FALSE); + + gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); + + set_item_text (item, label); + set_item_stock (item, NULL); + + g_free (label); + } + } + separator = gtk_separator_menu_item_new (); gtk_widget_show (separator); gtk_menu_shell_append (GTK_MENU_SHELL (menu), Index: libwnck/window.c =================================================================== --- libwnck/window.c.orig +++ libwnck/window.c @@ -110,6 +110,8 @@ struct _WnckWindowPrivate char *res_class; char *res_name; + + guint32 opacity; /* true if transient_for points to root window, * not another app window @@ -157,6 +159,7 @@ struct _WnckWindowPrivate guint need_update_startup_id : 1; guint need_update_wmclass : 1; guint need_update_wmhints : 1; + guint need_update_opacity : 1; guint need_update_frame_extents : 1; guint need_emit_name_changed : 1; @@ -173,6 +176,7 @@ enum { ICON_CHANGED, ACTIONS_CHANGED, GEOMETRY_CHANGED, + OPACITY_CHANGED, LAST_SIGNAL }; @@ -201,6 +205,7 @@ static void update_wintype (WnckWindow static void update_transient_for (WnckWindow *window); static void update_startup_id (WnckWindow *window); static void update_wmclass (WnckWindow *window); +static void update_opacity (WnckWindow *window); static void update_frame_extents (WnckWindow *window); static void unqueue_update (WnckWindow *window); static void queue_update (WnckWindow *window); @@ -407,6 +412,15 @@ wnck_window_class_init (WnckWindowClass NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + signals[OPACITY_CHANGED] = + g_signal_new ("opacity_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (WnckWindowClass, opacity_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -556,6 +570,7 @@ _wnck_window_create (Window xwindow window->priv->need_update_startup_id = TRUE; window->priv->need_update_wmclass = TRUE; window->priv->need_update_wmhints = TRUE; + window->priv->need_update_opacity = TRUE; window->priv->need_update_frame_extents = TRUE; window->priv->need_emit_name_changed = FALSE; window->priv->need_emit_icon_changed = FALSE; @@ -2320,6 +2335,29 @@ wnck_window_set_geometry (WnckWindow gravity_and_flags, x, y, width, height); } +guint +wnck_window_get_opacity (WnckWindow *window) +{ + guint64 o; + + g_return_val_if_fail (WNCK_IS_WINDOW (window), 0); + + o = ((guint64) window->priv->opacity * 1005) / G_MAXUINT32; + + return o / 10; +} + +void +wnck_window_set_opacity (WnckWindow *window, + guint opacity) +{ + g_return_if_fail (WNCK_IS_WINDOW (window)); + + _wnck_change_opacity (WNCK_SCREEN_XSCREEN (window->priv->screen), + wnck_window_get_xid (window), + (((guint64) opacity * G_MAXUINT32) / 100)); +} + /** * wnck_window_is_visible_on_workspace: * @window: a #WnckWindow. @@ -2565,6 +2603,13 @@ _wnck_window_process_property_notify (Wn window->priv->need_update_frame_extents = TRUE; queue_update (window); } + else if (xevent->xproperty.atom == + _wnck_atom_get ("_NET_WM_WINDOW_OPACITY")) + { + window->priv->need_update_opacity = TRUE; + queue_update (window); + } + } void @@ -3138,6 +3183,17 @@ update_frame_extents (WnckWindow *window } static void +update_opacity (WnckWindow *window) +{ + if (!window->priv->need_update_opacity) + return; + + window->priv->need_update_opacity = FALSE; + + window->priv->opacity = _wnck_get_opacity (window->priv->xwindow); +} + +static void force_update_now (WnckWindow *window) { WnckWindowState old_state; @@ -3172,6 +3228,7 @@ force_update_now (WnckWindow *window) */ update_workspace (window); /* emits signals */ update_actions (window); + update_opacity (window); update_frame_extents (window); /* emits signals */ get_icons (window); Index: libwnck/window.h =================================================================== --- libwnck/window.h.orig +++ libwnck/window.h @@ -272,6 +272,9 @@ struct _WnckWindowClass /* Changed size/position */ void (* geometry_changed) (WnckWindow *window); + /* Changed opacity */ + void (* opacity_changed) (WnckWindow *window); + /* Padding for future expansion */ void (* pad1) (void); void (* pad2) (void); @@ -401,6 +404,9 @@ void wnck_window_set_geometry (WnckWindo int width, int height); +guint wnck_window_get_opacity (WnckWindow *window); +void wnck_window_set_opacity (WnckWindow *window, guint opacity); + gboolean wnck_window_is_visible_on_workspace (WnckWindow *window, WnckWorkspace *workspace); gboolean wnck_window_is_on_workspace (WnckWindow *window, Index: libwnck/xutils.c =================================================================== --- libwnck/xutils.c.orig +++ libwnck/xutils.c @@ -1143,6 +1143,33 @@ _wnck_toggle_showing_desktop (Screen *s _wnck_error_trap_pop (); } +void +_wnck_change_opacity (Screen *screen, + Window xwindow, + guint32 opacity) +{ + XEvent xev; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = gdk_display; + xev.xclient.window = xwindow; + xev.xclient.message_type = _wnck_atom_get ("_NET_WM_WINDOW_OPACITY"); + xev.xclient.format = 32; + xev.xclient.data.l[0] = opacity; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, + RootWindowOfScreen (screen), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + char* _wnck_get_session_id (Window xwindow) { @@ -1317,6 +1344,19 @@ _wnck_get_frame_extents (Window xwindow return retval; } +guint32 +_wnck_get_opacity (Window xwindow) +{ + int val; + + if (_wnck_get_cardinal (xwindow, + _wnck_atom_get ("_NET_WM_WINDOW_OPACITY"), + &val)) + return val; + + return G_MAXUINT32; +} + void _wnck_select_input (Window xwindow, int mask) Index: libwnck/xutils.h =================================================================== --- libwnck/xutils.h.orig +++ libwnck/xutils.h @@ -110,6 +110,9 @@ void _wnck_activate_workspace (Screen *s void _wnck_change_viewport (Screen *screen, int x, int y); +void _wnck_change_opacity (Screen *screen, + Window xwindow, + guint32 opacity); char* _wnck_get_session_id (Window xwindow); int _wnck_get_pid (Window xwindow); @@ -125,6 +128,9 @@ gboolean _wnck_get_frame_extents (Windo int *top_frame, int *bottom_frame); +guint32 _wnck_get_opacity (Window xwindow); + + void _wnck_select_input (Window xwindow, int mask);