/* window action menu (ops on a single window) */
/* vim: set sw=2 et: */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2006-2007 Vincent Untz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, see .
*/
#include
#include
#include
#include
#include "window-action-menu.h"
#include "private.h"
/**
* SECTION:window-action-menu
* @short_description: a menu widget, used to manipulate a window.
* @see_also: #WnckWindow
* @stability: Unstable
*
* A #WnckActionMenu is a menu containing items to manipulate a window.
* Relevant actions are displayed in the menu, and updated if the window state
* changes. The content of this menu is synchronized with the similar menu
* available in Metacity.
*
*
*
* If there is only one workspace with a viewport, the #WnckActionMenu will
* contain items to move the window in the viewport as if the viewport feature
* was used to create workspaces. This is useful since viewport is generally
* used as an alternative way to create virtual desktops.
*
*
* The #WnckActionMenu does not support moving the window in the viewport if
* there are multiple workspaces on the screen: those two notions are so
* similar that having both at the same time would result in a menu which would
* be confusing to the user.
*
*
*/
typedef enum
{
CLOSE,
MINIMIZE,
MAXIMIZE,
ABOVE,
MOVE,
RESIZE,
PIN,
UNPIN,
LEFT,
RIGHT,
UP,
DOWN,
MOVE_TO_WORKSPACE
} WindowAction;
struct _WnckActionMenuPrivate
{
WnckWindow *window;
GtkWidget *minimize_item;
GtkWidget *maximize_item;
GtkWidget *above_item;
GtkWidget *move_item;
GtkWidget *resize_item;
GtkWidget *close_item;
GtkWidget *workspace_separator;
GtkWidget *pin_item;
GtkWidget *unpin_item;
GtkWidget *left_item;
GtkWidget *right_item;
GtkWidget *up_item;
GtkWidget *down_item;
GtkWidget *workspace_item;
guint idle_handler;
};
enum {
PROP_0,
PROP_WINDOW
};
G_DEFINE_TYPE_WITH_PRIVATE (WnckActionMenu, wnck_action_menu, GTK_TYPE_MENU);
static void wnck_action_menu_dispose (GObject *object);
static void window_weak_notify (gpointer data,
GObject *window);
static void refill_submenu_workspace (WnckActionMenu *menu);
static void refill_submenu_viewport (WnckActionMenu *menu);
static void
window_weak_notify (gpointer data,
GObject *window)
{
WNCK_ACTION_MENU(data)->priv->window = NULL;
gtk_widget_destroy (GTK_WIDGET (data));
}
static WnckActionMenu*
get_action_menu (GtkWidget *widget)
{
while (widget) {
if (GTK_IS_MENU_ITEM (widget))
widget = gtk_widget_get_parent (widget);
if (WNCK_IS_ACTION_MENU (widget))
return WNCK_ACTION_MENU (widget);
widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
if (widget == NULL)
break;
}
return NULL;
}
static void
item_activated_callback (GtkWidget *menu_item,
gpointer data)
{
WnckActionMenu *menu;
WnckWindow *window;
WindowAction action = GPOINTER_TO_INT (data);
WnckScreen *screen;
gboolean viewport_mode;
menu = get_action_menu (menu_item);
if (menu == NULL)
return;
window = menu->priv->window;
screen = wnck_window_get_screen (window);
viewport_mode = wnck_screen_get_workspace_count (screen) == 1 &&
wnck_workspace_is_virtual (wnck_screen_get_workspace (screen,
0));
switch (action)
{
case CLOSE:
/* In an activate callback, so gtk_get_current_event_time() suffices */
wnck_window_close (window,
gtk_get_current_event_time ());
break;
case MINIMIZE:
if (wnck_window_is_minimized (window))
wnck_window_unminimize (window,
gtk_get_current_event_time ());
else
wnck_window_minimize (window);
break;
case MAXIMIZE:
if (wnck_window_is_maximized (window))
wnck_window_unmaximize (window);
else
wnck_window_maximize (window);
break;
case ABOVE:
if (wnck_window_is_above (window))
wnck_window_unmake_above (window);
else
wnck_window_make_above (window);
break;
case MOVE:
wnck_window_keyboard_move (window);
break;
case RESIZE:
wnck_window_keyboard_size (window);
break;
case PIN:
if (!viewport_mode)
wnck_window_pin (window);
else
wnck_window_stick (window);
break;
case UNPIN:
if (!viewport_mode)
wnck_window_unpin (window);
else
wnck_window_unstick (window);
break;
case LEFT:
if (!viewport_mode)
{
WnckWorkspace *workspace;
workspace = wnck_workspace_get_neighbor (wnck_window_get_workspace (window),
WNCK_MOTION_LEFT);
wnck_window_move_to_workspace (window, workspace);
}
else
{
int width, xw, yw, ww, hw;
width = wnck_screen_get_width (screen);
wnck_window_get_geometry (window, &xw, &yw, &ww, &hw);
wnck_window_unstick (window);
wnck_window_set_geometry (window, 0,
WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y,
xw - width, yw,
ww, hw);
}
break;
case RIGHT:
if (!viewport_mode)
{
WnckWorkspace *workspace;
workspace = wnck_workspace_get_neighbor (wnck_window_get_workspace (window),
WNCK_MOTION_RIGHT);
wnck_window_move_to_workspace (window, workspace);
}
else
{
int width, xw, yw, ww, hw;
width = wnck_screen_get_width (screen);
wnck_window_get_geometry (window, &xw, &yw, &ww, &hw);
wnck_window_unstick (window);
wnck_window_set_geometry (window, 0,
WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y,
xw + width, yw,
ww, hw);
}
break;
case UP:
if (!viewport_mode)
{
WnckWorkspace *workspace;
workspace = wnck_workspace_get_neighbor (wnck_window_get_workspace (window),
WNCK_MOTION_UP);
wnck_window_move_to_workspace (window, workspace);
}
else
{
int height, xw, yw, ww, hw;
height = wnck_screen_get_height (screen);
wnck_window_get_geometry (window, &xw, &yw, &ww, &hw);
wnck_window_unstick (window);
wnck_window_set_geometry (window, 0,
WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y,
xw, yw - height,
ww, hw);
}
break;
case DOWN:
if (!viewport_mode)
{
WnckWorkspace *workspace;
workspace = wnck_workspace_get_neighbor (wnck_window_get_workspace (window),
WNCK_MOTION_DOWN);
wnck_window_move_to_workspace (window, workspace);
}
else
{
int height, xw, yw, ww, hw;
height = wnck_screen_get_height (screen);
wnck_window_get_geometry (window, &xw, &yw, &ww, &hw);
wnck_window_unstick (window);
wnck_window_set_geometry (window, 0,
WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y,
xw, yw + height,
ww, hw);
}
break;
case MOVE_TO_WORKSPACE:
if (!viewport_mode)
{
int workspace_index;
WnckWorkspace *workspace;
workspace_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item),
"workspace"));
workspace = wnck_screen_get_workspace (screen, workspace_index);
wnck_window_move_to_workspace (window, workspace);
}
else
{
WnckWorkspace *workspace;
int new_viewport_x, new_viewport_y;
int xw, yw, ww, hw;
int viewport_x, viewport_y;
new_viewport_x = GPOINTER_TO_INT (
g_object_get_data (G_OBJECT (menu_item),
"viewport_x"));
new_viewport_y = GPOINTER_TO_INT (
g_object_get_data (G_OBJECT (menu_item),
"viewport_y"));
workspace = wnck_screen_get_workspace (screen, 0);
wnck_window_get_geometry (window, &xw, &yw, &ww, &hw);
viewport_x = wnck_workspace_get_viewport_x (workspace);
viewport_y = wnck_workspace_get_viewport_y (workspace);
wnck_window_unstick (window);
wnck_window_set_geometry (window, 0,
WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y,
xw + new_viewport_x - viewport_x,
yw + new_viewport_y - viewport_y,
ww, hw);
}
break;
default:
g_assert_not_reached ();
}
}
static void
set_item_text (GtkWidget *mi,
const char *text)
{
GtkLabel *label;
label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (mi)));
gtk_label_set_text_with_mnemonic (label, text);
gtk_label_set_use_underline (label, TRUE);
}
static gboolean
update_menu_state (WnckActionMenu *menu)
{
WnckActionMenuPrivate *priv;
WnckWindowActions actions;
WnckScreen *screen;
WnckWorkspace *workspace;
gboolean viewport_mode;
gboolean move_workspace_sensitive;
priv = menu->priv;
priv->idle_handler = 0;
actions = wnck_window_get_actions (priv->window);
screen = wnck_window_get_screen (priv->window);
viewport_mode = wnck_screen_get_workspace_count (screen) == 1 &&
wnck_workspace_is_virtual (wnck_screen_get_workspace (screen,
0));
move_workspace_sensitive = viewport_mode ||
(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0;
if (wnck_window_is_minimized (priv->window))
{
set_item_text (priv->minimize_item, _("Unmi_nimize"));
gtk_widget_set_sensitive (priv->minimize_item,
(actions & WNCK_WINDOW_ACTION_UNMINIMIZE) != 0);
}
else
{
set_item_text (priv->minimize_item, _("Mi_nimize"));
gtk_widget_set_sensitive (priv->minimize_item,
(actions & WNCK_WINDOW_ACTION_MINIMIZE) != 0);
}
if (wnck_window_is_maximized (priv->window))
{
set_item_text (priv->maximize_item, _("Unma_ximize"));
gtk_widget_set_sensitive (priv->maximize_item,
(actions & WNCK_WINDOW_ACTION_UNMAXIMIZE) != 0);
}
else
{
set_item_text (priv->maximize_item, _("Ma_ximize"));
gtk_widget_set_sensitive (priv->maximize_item,
(actions & WNCK_WINDOW_ACTION_MAXIMIZE) != 0);
}
g_signal_handlers_block_by_func (G_OBJECT (priv->above_item),
item_activated_callback,
GINT_TO_POINTER (ABOVE));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->above_item),
wnck_window_is_above (priv->window));
g_signal_handlers_unblock_by_func (G_OBJECT (priv->above_item),
item_activated_callback,
GINT_TO_POINTER (ABOVE));
gtk_widget_set_sensitive (priv->above_item,
(actions & WNCK_WINDOW_ACTION_ABOVE) != 0);
g_signal_handlers_block_by_func (G_OBJECT (priv->pin_item),
item_activated_callback,
GINT_TO_POINTER (PIN));
g_signal_handlers_block_by_func (G_OBJECT (priv->unpin_item),
item_activated_callback,
GINT_TO_POINTER (UNPIN));
if ((viewport_mode && wnck_window_is_sticky (priv->window)) ||
(!viewport_mode && wnck_window_is_pinned (priv->window)))
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->pin_item),
TRUE);
else
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->unpin_item),
TRUE);
g_signal_handlers_unblock_by_func (G_OBJECT (priv->pin_item),
item_activated_callback,
GINT_TO_POINTER (PIN));
g_signal_handlers_unblock_by_func (G_OBJECT (priv->unpin_item),
item_activated_callback,
GINT_TO_POINTER (UNPIN));
gtk_widget_set_sensitive (priv->pin_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->unpin_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->close_item,
(actions & WNCK_WINDOW_ACTION_CLOSE) != 0);
gtk_widget_set_sensitive (priv->move_item,
(actions & WNCK_WINDOW_ACTION_MOVE) != 0);
gtk_widget_set_sensitive (priv->resize_item,
(actions & WNCK_WINDOW_ACTION_RESIZE) != 0);
gtk_widget_set_sensitive (priv->workspace_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->left_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->right_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->up_item,
move_workspace_sensitive);
gtk_widget_set_sensitive (priv->down_item,
move_workspace_sensitive);
workspace = wnck_window_get_workspace (priv->window);
if (viewport_mode && !wnck_window_is_sticky (priv->window))
{
int window_x, window_y;
int viewport_x, viewport_y;
int viewport_width, viewport_height;
int screen_width, screen_height;
if (!workspace)
workspace = wnck_screen_get_workspace (screen, 0);
wnck_window_get_geometry (priv->window, &window_x, &window_y, NULL, NULL);
viewport_x = wnck_workspace_get_viewport_x (workspace);
viewport_y = wnck_workspace_get_viewport_y (workspace);
window_x += viewport_x;
window_y += viewport_y;
viewport_width = wnck_workspace_get_width (workspace);
viewport_height = wnck_workspace_get_height (workspace);
screen_width = wnck_screen_get_width (screen);
screen_height = wnck_screen_get_height (screen);
if (window_x >= screen_width)
gtk_widget_show (priv->left_item);
else
gtk_widget_hide (priv->left_item);
if (window_x < viewport_width - screen_width)
gtk_widget_show (priv->right_item);
else
gtk_widget_hide (priv->right_item);
if (window_y >= screen_height)
gtk_widget_show (priv->up_item);
else
gtk_widget_hide (priv->up_item);
if (window_y < viewport_height - screen_height)
gtk_widget_show (priv->down_item);
else
gtk_widget_hide (priv->down_item);
}
else if (!viewport_mode && workspace && !wnck_window_is_pinned (priv->window))
{
if (wnck_workspace_get_neighbor (workspace, WNCK_MOTION_LEFT))
gtk_widget_show (priv->left_item);
else
gtk_widget_hide (priv->left_item);
if (wnck_workspace_get_neighbor (workspace, WNCK_MOTION_RIGHT))
gtk_widget_show (priv->right_item);
else
gtk_widget_hide (priv->right_item);
if (wnck_workspace_get_neighbor (workspace, WNCK_MOTION_UP))
gtk_widget_show (priv->up_item);
else
gtk_widget_hide (priv->up_item);
if (wnck_workspace_get_neighbor (workspace, WNCK_MOTION_DOWN))
gtk_widget_show (priv->down_item);
else
gtk_widget_hide (priv->down_item);
}
else
{
gtk_widget_hide (priv->left_item);
gtk_widget_hide (priv->right_item);
gtk_widget_hide (priv->up_item);
gtk_widget_hide (priv->down_item);
}
if (viewport_mode)
{
int viewport_width, viewport_height;
int screen_width, screen_height;
viewport_width = wnck_workspace_get_width (workspace);
viewport_height = wnck_workspace_get_height (workspace);
screen_width = wnck_screen_get_width (screen);
screen_height = wnck_screen_get_height (screen);
gtk_widget_show (priv->workspace_separator);
gtk_widget_show (priv->pin_item);
gtk_widget_show (priv->unpin_item);
if (viewport_width >= 2 * screen_width ||
viewport_height >= 2 * screen_height)
{
gtk_widget_show (priv->workspace_item);
refill_submenu_viewport (menu);
}
else
{
gtk_widget_hide (priv->workspace_item);
gtk_menu_popdown (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (priv->workspace_item))));
}
}
else if (wnck_screen_get_workspace_count (screen) > 1)
{
gtk_widget_show (priv->workspace_separator);
gtk_widget_show (priv->pin_item);
gtk_widget_show (priv->unpin_item);
gtk_widget_show (priv->workspace_item);
refill_submenu_workspace (menu);
}
else
{
gtk_widget_hide (priv->workspace_separator);
gtk_widget_hide (priv->pin_item);
gtk_widget_hide (priv->unpin_item);
gtk_widget_hide (priv->workspace_item);
gtk_menu_popdown (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (priv->workspace_item))));
}
gtk_menu_reposition (GTK_MENU (menu));
return FALSE;
}
static void
queue_update (WnckActionMenu *menu)
{
if (menu->priv->idle_handler == 0)
menu->priv->idle_handler = g_idle_add ((GSourceFunc)update_menu_state,
menu);
}
static void
state_changed_callback (WnckWindow *window,
WnckWindowState changed_mask,
WnckWindowState new_state,
gpointer data)
{
queue_update (WNCK_ACTION_MENU (data));
}
static void
actions_changed_callback (WnckWindow *window,
WnckWindowActions changed_mask,
WnckWindowActions new_actions,
gpointer data)
{
queue_update (WNCK_ACTION_MENU (data));
}
static void
workspace_changed_callback (WnckWindow *window,
gpointer data)
{
queue_update (WNCK_ACTION_MENU (data));
}
static void
screen_workspace_callback (WnckWindow *window,
WnckWorkspace *space,
gpointer data)
{
queue_update (WNCK_ACTION_MENU (data));
}
static void
viewports_changed_callback (WnckWindow *window,
gpointer data)
{
queue_update (WNCK_ACTION_MENU (data));
}
static GtkWidget*
make_radio_menu_item (WindowAction action,
GSList **group,
const gchar *mnemonic_text)
{
GtkWidget *mi;
mi = gtk_radio_menu_item_new_with_mnemonic (*group, mnemonic_text);
*group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (mi));
g_signal_connect (G_OBJECT (mi), "activate",
G_CALLBACK (item_activated_callback),
GINT_TO_POINTER (action));
gtk_widget_show (mi);
return mi;
}
static GtkWidget*
make_check_menu_item (WindowAction action,
const gchar *mnemonic_text)
{
GtkWidget *mi;
mi = gtk_check_menu_item_new_with_mnemonic (mnemonic_text);
g_signal_connect (G_OBJECT (mi), "activate",
G_CALLBACK (item_activated_callback),
GINT_TO_POINTER (action));
gtk_widget_show (mi);
return mi;
}
static GtkWidget*
make_menu_item (WindowAction action)
{
GtkWidget *mi;
mi = gtk_menu_item_new_with_label ("");
g_signal_connect (G_OBJECT (mi), "activate",
G_CALLBACK (item_activated_callback),
GINT_TO_POINTER (action));
gtk_widget_show (mi);
return mi;
}
static char *
get_workspace_name_with_accel (WnckWindow *window,
int index)
{
const char *name;
int number;
name = wnck_workspace_get_name (wnck_screen_get_workspace (wnck_window_get_screen (window),
index));
g_assert (name != NULL);
/*
* If the name is of the form "Workspace x" where x is an unsigned
* integer, insert a '_' before the number if it is less than 10 and
* return it
*/
number = 0;
if (sscanf (name, _("Workspace %d"), &number) == 1) {
/* Keep this in sync with what is in refill_submenu_viewport() */
char *new_name;
/*
* Above name is a pointer into the Workspace struct. Here we make
* a copy copy so we can have our wicked way with it.
*/
if (number == 10)
new_name = g_strdup_printf (_("Workspace 1_0"));
else
new_name = g_strdup_printf (_("Workspace %s%d"),
number < 10 ? "_" : "",
number);
return new_name;
}
else {
/*
* Otherwise this is just a normal name. Escape any _ characters so that
* the user's workspace names do not get mangled. If the number is less
* than 10 we provide an accelerator.
*/
char *new_name;
const char *source;
char *dest;
/*
* Assume the worst case, that every character is a _. We also
* provide memory for " (_#)"
*/
new_name = g_malloc0 (strlen (name) * 2 + 6 + 1);
/*
* Now iterate down the strings, adding '_' to escape as we go
*/
dest = new_name;
source = name;
while (*source != '\0') {
if (*source == '_')
*dest++ = '_';
*dest++ = *source++;
}
/* People don't start at workstation 0, but workstation 1 */
if (index < 9) {
g_snprintf (dest, 6, " (_%d)", index + 1);
}
else if (index == 9) {
g_snprintf (dest, 6, " (_0)");
}
return new_name;
}
}
static void
refill_submenu_workspace (WnckActionMenu *menu)
{
GtkWidget *submenu;
GList *children;
GList *l;
int num_workspaces, window_space, i;
WnckWorkspace *workspace;
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu->priv->workspace_item));
/* Remove existing items */
children = gtk_container_get_children (GTK_CONTAINER (submenu));
for (l = children; l; l = l->next)
gtk_container_remove (GTK_CONTAINER (submenu), l->data);
g_list_free (children);
workspace = wnck_window_get_workspace (menu->priv->window);
num_workspaces = wnck_screen_get_workspace_count (wnck_window_get_screen (menu->priv->window));
if (workspace)
window_space = wnck_workspace_get_number (workspace);
else
window_space = -1;
for (i = 0; i < num_workspaces; i++)
{
char *name;
GtkWidget *item;
name = get_workspace_name_with_accel (menu->priv->window, i);
item = make_menu_item (MOVE_TO_WORKSPACE);
g_object_set_data (G_OBJECT (item), "workspace", GINT_TO_POINTER (i));
if (i == window_space)
gtk_widget_set_sensitive (item, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
set_item_text (item, name);
g_free (name);
}
gtk_menu_reposition (GTK_MENU (submenu));
}
static void
refill_submenu_viewport (WnckActionMenu *menu)
{
GtkWidget *submenu;
GList *children;
GList *l;
WnckScreen *screen;
WnckWorkspace *workspace;
int window_x, window_y;
int viewport_x, viewport_y;
int viewport_width, viewport_height;
int screen_width, screen_height;
int x, y;
int number;
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu->priv->workspace_item));
/* Remove existing items */
children = gtk_container_get_children (GTK_CONTAINER (submenu));
for (l = children; l; l = l->next)
gtk_container_remove (GTK_CONTAINER (submenu), l->data);
g_list_free (children);
screen = wnck_window_get_screen (menu->priv->window);
workspace = wnck_screen_get_workspace (screen, 0);
wnck_window_get_geometry (menu->priv->window,
&window_x, &window_y, NULL, NULL);
viewport_x = wnck_workspace_get_viewport_x (workspace);
viewport_y = wnck_workspace_get_viewport_y (workspace);
window_x += viewport_x;
window_y += viewport_y;
viewport_width = wnck_workspace_get_width (workspace);
viewport_height = wnck_workspace_get_height (workspace);
screen_width = wnck_screen_get_width (screen);
screen_height = wnck_screen_get_height (screen);
number = 1;
for (y = 0; y < viewport_height; y += screen_height)
{
char *label;
GtkWidget *item;
for (x = 0; x < viewport_width; x += screen_width)
{
/* Keep this in sync with what is in get_workspace_name_with_accel()
*/
if (number == 10)
label = g_strdup_printf (_("Workspace 1_0"));
else
label = g_strdup_printf (_("Workspace %s%d"),
number < 10 ? "_" : "",
number);
number++;
item = make_menu_item (MOVE_TO_WORKSPACE);
g_object_set_data (G_OBJECT (item), "viewport_x",
GINT_TO_POINTER (x));
g_object_set_data (G_OBJECT (item), "viewport_y",
GINT_TO_POINTER (y));
if (window_x >= x && window_x < x + screen_width &&
window_y >= y && window_y < y + screen_height)
gtk_widget_set_sensitive (item, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
set_item_text (item, label);
g_free (label);
}
}
gtk_menu_reposition (GTK_MENU (submenu));
}
static void
wnck_action_menu_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
WnckActionMenu *menu;
g_return_if_fail (WNCK_IS_ACTION_MENU (object));
menu = WNCK_ACTION_MENU (object);
switch (prop_id)
{
case PROP_WINDOW:
g_value_set_pointer (value, menu->priv->window);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
wnck_action_menu_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
WnckActionMenu *menu;
g_return_if_fail (WNCK_IS_ACTION_MENU (object));
menu = WNCK_ACTION_MENU (object);
switch (prop_id)
{
case PROP_WINDOW:
g_return_if_fail (WNCK_IS_WINDOW (g_value_get_pointer (value)));
menu->priv->window = g_value_get_pointer (value);
g_object_notify (G_OBJECT (menu), "window");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
wnck_action_menu_init (WnckActionMenu *menu)
{
menu->priv = wnck_action_menu_get_instance_private (menu);
menu->priv->window = NULL;
menu->priv->minimize_item = NULL;
menu->priv->maximize_item = NULL;
menu->priv->above_item = NULL;
menu->priv->move_item = NULL;
menu->priv->resize_item = NULL;
menu->priv->close_item = NULL;
menu->priv->workspace_separator = NULL;
menu->priv->pin_item = NULL;
menu->priv->unpin_item = NULL;
menu->priv->left_item = NULL;
menu->priv->right_item = NULL;
menu->priv->up_item = NULL;
menu->priv->down_item = NULL;
menu->priv->workspace_item = NULL;
menu->priv->idle_handler = 0;
}
static GObject *
wnck_action_menu_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *obj;
WnckActionMenu *menu;
WnckActionMenuPrivate *priv;
GtkWidget *submenu;
GtkWidget *separator;
GSList *pin_group;
WnckScreen *screen;
obj = G_OBJECT_CLASS (wnck_action_menu_parent_class)->constructor (type,
n_construct_properties,
construct_properties);
menu = WNCK_ACTION_MENU (obj);
priv = menu->priv;
if (priv->window == NULL)
{
g_warning ("No window specified during creation of the action menu");
return obj;
}
g_object_weak_ref (G_OBJECT (priv->window), window_weak_notify, menu);
priv->minimize_item = make_menu_item (MINIMIZE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->minimize_item);
priv->maximize_item = make_menu_item (MAXIMIZE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->maximize_item);
priv->move_item = make_menu_item (MOVE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->move_item);
set_item_text (priv->move_item, _("_Move"));
priv->resize_item = make_menu_item (RESIZE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->resize_item);
set_item_text (priv->resize_item, _("_Resize"));
priv->workspace_separator = separator = gtk_separator_menu_item_new ();
gtk_widget_show (separator);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
separator);
priv->above_item = make_check_menu_item (ABOVE,
_("Always On _Top"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->above_item);
pin_group = NULL;
priv->pin_item = make_radio_menu_item (PIN, &pin_group,
_("_Always on Visible Workspace"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->pin_item);
priv->unpin_item = make_radio_menu_item (UNPIN, &pin_group,
_("_Only on This Workspace"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->unpin_item);
priv->left_item = make_menu_item (LEFT);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->left_item);
set_item_text (priv->left_item, _("Move to Workspace _Left"));
priv->right_item = make_menu_item (RIGHT);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->right_item);
set_item_text (priv->right_item, _("Move to Workspace R_ight"));
priv->up_item = make_menu_item (UP);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->up_item);
set_item_text (priv->up_item, _("Move to Workspace _Up"));
priv->down_item = make_menu_item (DOWN);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->down_item);
set_item_text (priv->down_item, _("Move to Workspace _Down"));
priv->workspace_item = gtk_menu_item_new_with_mnemonic (_("Move to Another _Workspace"));
gtk_widget_show (priv->workspace_item);
submenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->workspace_item),
submenu);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->workspace_item);
separator = gtk_separator_menu_item_new ();
gtk_widget_show (separator);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
separator);
priv->close_item = make_menu_item (CLOSE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
priv->close_item);
set_item_text (priv->close_item, _("_Close"));
g_signal_connect_object (G_OBJECT (priv->window),
"state_changed",
G_CALLBACK (state_changed_callback),
G_OBJECT (menu),
0);
g_signal_connect_object (G_OBJECT (priv->window),
"actions_changed",
G_CALLBACK (actions_changed_callback),
G_OBJECT (menu),
0);
g_signal_connect_object (G_OBJECT (priv->window),
"workspace_changed",
G_CALLBACK (workspace_changed_callback),
G_OBJECT (menu),
0);
screen = wnck_window_get_screen (priv->window);
g_signal_connect_object (G_OBJECT (screen),
"workspace_created",
G_CALLBACK (screen_workspace_callback),
G_OBJECT (menu),
0);
g_signal_connect_object (G_OBJECT (screen),
"workspace_destroyed",
G_CALLBACK (screen_workspace_callback),
G_OBJECT (menu),
0);
g_signal_connect_object (G_OBJECT (screen),
"viewports_changed",
G_CALLBACK (viewports_changed_callback),
G_OBJECT (menu),
0);
update_menu_state (menu);
return obj;
}
static void
wnck_action_menu_class_init (WnckActionMenuClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructor = wnck_action_menu_constructor;
object_class->get_property = wnck_action_menu_get_property;
object_class->set_property = wnck_action_menu_set_property;
object_class->dispose = wnck_action_menu_dispose;
g_object_class_install_property (object_class,
PROP_WINDOW,
g_param_spec_pointer ("window",
"Window",
"The window that will be manipulated through this menu",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
wnck_action_menu_dispose (GObject *object)
{
WnckActionMenu *menu;
menu = WNCK_ACTION_MENU (object);
if (menu->priv->idle_handler)
{
g_source_remove (menu->priv->idle_handler);
menu->priv->idle_handler = 0;
}
if (WNCK_IS_WINDOW (menu->priv->window))
{
WnckScreen *screen;
g_object_weak_unref (G_OBJECT (menu->priv->window), window_weak_notify, menu);
g_signal_handlers_disconnect_by_data (menu->priv->window, menu);
screen = wnck_window_get_screen (menu->priv->window);
g_signal_handlers_disconnect_by_data (screen, menu);
menu->priv->window = NULL;
}
G_OBJECT_CLASS (wnck_action_menu_parent_class)->dispose (object);
}
/**
* wnck_action_menu_new:
* @window: the #WnckWindow for which a menu will be created.
*
* Creates a new #WnckActionMenu. The #WnckActionMenu will be filled with menu
* items for window operations on @window.
*
* Return value: a newly created #WnckActionMenu.
*
* Since: 2.22
**/
GtkWidget*
wnck_action_menu_new (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return g_object_new (WNCK_TYPE_ACTION_MENU,
"window", window,
NULL);
}