summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrhp <rhp>2001-06-09 05:14:43 +0000
committerrhp <rhp>2001-06-09 05:14:43 +0000
commitd0f6283cf5e11a3c15fd6c7b7e6d7beb7bf55900 (patch)
tree7491b5c4504d661c52f6b9888a252f33f4f97321
parent6631763c96c6ccae0590d2ff098e1d66423b4317 (diff)
downloadmetacity-d0f6283cf5e11a3c15fd6c7b7e6d7beb7bf55900.tar.gz
workspace menu
-rw-r--r--src/display.c59
-rw-r--r--src/display.h3
-rw-r--r--src/menu.c198
-rw-r--r--src/screen.c22
-rw-r--r--src/screen.h3
-rw-r--r--src/uislave/menu.c198
-rw-r--r--src/uislave/messages.h8
-rw-r--r--src/window.c27
-rw-r--r--src/window.h3
-rw-r--r--src/workspace.c79
-rw-r--r--src/workspace.h1
11 files changed, 570 insertions, 31 deletions
diff --git a/src/display.c b/src/display.c
index 7858951b..df2169a9 100644
--- a/src/display.c
+++ b/src/display.c
@@ -84,7 +84,9 @@ meta_display_open (const char *name)
"MOTIF_WM_HINTS",
"_NET_WM_STATE_SHADED",
"_NET_WM_STATE_MAXIMIZED_HORZ",
- "_NET_WM_STATE_MAXIMIZED_VERT"
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_DESKTOP",
+ "_NET_NUMBER_OF_DESKTOPS"
};
Atom atoms[G_N_ELEMENTS(atom_names)];
@@ -111,13 +113,29 @@ meta_display_open (const char *name)
display->name = g_strdup (XDisplayName (name));
display->xdisplay = xdisplay;
display->error_traps = NULL;
-
+ display->server_grab_count = 0;
display->workspaces = NULL;
/* we have to go ahead and do this so error handlers work */
all_displays = g_slist_prepend (all_displays, display);
meta_display_init_keys (display);
+
+ XInternAtoms (display->xdisplay, atom_names, G_N_ELEMENTS (atom_names),
+ False, atoms);
+ display->atom_net_wm_name = atoms[0];
+ display->atom_wm_protocols = atoms[1];
+ display->atom_wm_take_focus = atoms[2];
+ display->atom_wm_delete_window = atoms[3];
+ display->atom_wm_state = atoms[4];
+ display->atom_net_close_window = atoms[5];
+ display->atom_net_wm_state = atoms[6];
+ display->atom_motif_wm_hints = atoms[7];
+ display->atom_net_wm_state_shaded = atoms[8];
+ display->atom_net_wm_state_maximized_horz = atoms[9];
+ display->atom_net_wm_state_maximized_vert = atoms[10];
+ display->atom_net_wm_desktop = atoms[11];
+ display->atom_net_number_of_desktops = atoms[12];
screens = NULL;
i = 0;
@@ -151,22 +169,6 @@ meta_display_open (const char *name)
display);
display->window_ids = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
-
- display->server_grab_count = 0;
-
- XInternAtoms (display->xdisplay, atom_names, G_N_ELEMENTS (atom_names),
- False, atoms);
- display->atom_net_wm_name = atoms[0];
- display->atom_wm_protocols = atoms[1];
- display->atom_wm_take_focus = atoms[2];
- display->atom_wm_delete_window = atoms[3];
- display->atom_wm_state = atoms[4];
- display->atom_net_close_window = atoms[5];
- display->atom_net_wm_state = atoms[6];
- display->atom_motif_wm_hints = atoms[7];
- display->atom_net_wm_state_shaded = atoms[8];
- display->atom_net_wm_state_maximized_horz = atoms[9];
- display->atom_net_wm_state_maximized_vert = atoms[10];
display->double_click_time = 250;
display->last_button_time = 0;
@@ -551,6 +553,27 @@ event_queue_callback (MetaEventQueue *queue,
*/
meta_window_delete (window, CurrentTime);
}
+ else if (event->xclient.message_type ==
+ display->atom_net_wm_desktop)
+ {
+ int space;
+ MetaWorkspace *workspace;
+
+ space = event->xclient.data.l[0];
+
+ meta_verbose ("Request to move %s to screen workspace %d\n",
+ window->desc, space);
+
+ workspace =
+ meta_display_get_workspace_by_screen_index (display,
+ window->screen,
+ space);
+
+ if (workspace)
+ meta_window_change_workspace (window, workspace);
+ else
+ meta_verbose ("No such workspace %d for screen\n", space);
+ }
}
break;
case MappingNotify:
diff --git a/src/display.h b/src/display.h
index 45be6ae8..1b3ef03d 100644
--- a/src/display.h
+++ b/src/display.h
@@ -50,6 +50,8 @@ struct _MetaDisplay
Atom atom_net_wm_state_shaded;
Atom atom_net_wm_state_maximized_horz;
Atom atom_net_wm_state_maximized_vert;
+ Atom atom_net_wm_desktop;
+ Atom atom_net_number_of_desktops;
/* This is the actual window from focus events,
* not the one we last set
@@ -106,5 +108,4 @@ MetaWorkspace* meta_display_get_workspace_by_screen_index (MetaDisplay *displa
MetaScreen *screen,
int index);
-
#endif
diff --git a/src/menu.c b/src/menu.c
index 81015dd6..5e77abc9 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -22,6 +22,7 @@
#include "menu.h"
#include "main.h"
#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
typedef struct _MenuItem MenuItem;
typedef struct _MenuData MenuData;
@@ -44,9 +45,10 @@ static void activate_cb (GtkWidget *menuitem, gpointer data);
static GtkWidget *menu = NULL;
static MenuItem menuitems[] = {
- { META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("Close") },
- { META_MESSAGE_MENU_MINIMIZE, NULL, N_("Minimize") },
- { META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Maximize") }
+ { META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("_Close") },
+ { META_MESSAGE_MENU_MINIMIZE, NULL, N_("_Minimize") },
+ { META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Ma_ximize") },
+ { META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }
};
static void
@@ -71,6 +73,67 @@ popup_position_func (GtkMenu *menu,
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
}
+static gint
+get_num_desktops (void)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *num;
+ int result;
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ gdk_atom_intern ("_NET_NUMBER_OF_DESKTOPS", FALSE),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&num);
+
+ if (type != XA_CARDINAL)
+ return 0;
+
+ result = *num;
+
+ XFree (num);
+
+ return result;
+}
+
+static gulong
+get_current_desktop (GdkWindow *window)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *num;
+ gulong result;
+ int err;
+
+ gdk_error_trap_push ();
+ type = None;
+ XGetWindowProperty (gdk_display, GDK_WINDOW_XID (window),
+ gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&num);
+ err = gdk_error_trap_pop ();
+ if (err != Success)
+ meta_ui_warning ("Error %d getting _NET_WM_DESKTOP\n", err);
+
+ if (type != XA_CARDINAL)
+ {
+ meta_ui_warning ("_NET_WM_DESKTOP has wrong type %s\n", gdk_atom_name (type));
+ return -1;
+ }
+
+ result = *num;
+
+ XFree (num);
+
+ return result;
+}
+
void
meta_window_menu_show (gulong xwindow,
int root_x, int root_y,
@@ -82,6 +145,8 @@ meta_window_menu_show (gulong xwindow,
int i;
GdkWindow *window;
GdkPoint *pt;
+ int n_workspaces;
+ int current_workspace;
if (menu)
gtk_widget_destroy (menu);
@@ -110,7 +175,7 @@ meta_window_menu_show (gulong xwindow,
{
GtkWidget *image;
- mi = gtk_image_menu_item_new_with_label (menuitems[i].label);
+ mi = gtk_image_menu_item_new_with_mnemonic (menuitems[i].label);
image = gtk_image_new_from_stock (menuitems[i].stock_id,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
@@ -119,7 +184,7 @@ meta_window_menu_show (gulong xwindow,
}
else
{
- mi = gtk_menu_item_new_with_label (menuitems[i].label);
+ mi = gtk_menu_item_new_with_mnemonic (menuitems[i].label);
}
if (insensitive & menuitems[i].op)
@@ -142,6 +207,60 @@ meta_window_menu_show (gulong xwindow,
}
++i;
}
+
+ if (ops & META_MESSAGE_MENU_WORKSPACES)
+ {
+ n_workspaces = get_num_desktops ();
+ current_workspace = get_current_desktop (window);
+
+ meta_ui_warning ("Creating %d workspace menu current %d\n",
+ n_workspaces, current_workspace);
+
+ if (n_workspaces > 0 && current_workspace >= 0)
+ {
+ i = 0;
+ while (i < n_workspaces)
+ {
+ char *label;
+ GtkWidget *mi;
+ MenuData *md;
+
+ label = g_strdup_printf (_("Move to workspace _%d\n"),
+ i + 1);
+
+ mi = gtk_menu_item_new_with_mnemonic (label);
+
+ g_free (label);
+
+ if (current_workspace == i ||
+ insensitive & META_MESSAGE_MENU_WORKSPACES)
+ gtk_widget_set_sensitive (mi, FALSE);
+
+ md = g_new (MenuData, 1);
+
+ md->window = window;
+ md->op = META_MESSAGE_MENU_WORKSPACES;
+
+ g_object_set_data (G_OBJECT (mi),
+ "workspace",
+ GINT_TO_POINTER (i));
+
+ gtk_signal_connect (GTK_OBJECT (mi),
+ "activate",
+ GTK_SIGNAL_FUNC (activate_cb),
+ md);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ mi);
+
+ gtk_widget_show (mi);
+
+ ++i;
+ }
+ }
+ }
+ else
+ meta_ui_warning ("not creating workspace menu\n");
gtk_signal_connect (GTK_OBJECT (menu),
"destroy",
@@ -197,6 +316,58 @@ close_window (GdkWindow *window)
}
static void
+wmspec_change_state (gboolean add,
+ GdkWindow *window,
+ GdkAtom state1,
+ GdkAtom state2)
+{
+ XEvent xev;
+ Atom op;
+
+ if (add)
+ op = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE);
+ else
+ op = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = op;
+ xev.xclient.data.l[1] = state1;
+ xev.xclient.data.l[2] = state2;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
+wmspec_change_desktop (GdkWindow *window,
+ gint desktop)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = desktop;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
activate_cb (GtkWidget *menuitem, gpointer data)
{
MenuData *md;
@@ -219,6 +390,23 @@ activate_cb (GtkWidget *menuitem, gpointer data)
gdk_error_trap_pop ();
break;
+ case META_MESSAGE_MENU_SHADE:
+ wmspec_change_state (TRUE, md->window,
+ gdk_atom_intern ("_NET_WM_STATE_SHADED", FALSE),
+ 0);
+ break;
+
+ case META_MESSAGE_MENU_WORKSPACES:
+ {
+ int workspace;
+
+ workspace = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
+ "workspace"));
+
+ wmspec_change_desktop (md->window, workspace);
+ }
+ break;
+
default:
meta_ui_warning (G_STRLOC": Unknown window op\n");
break;
diff --git a/src/screen.c b/src/screen.c
index 1c262cd5..75851c66 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -460,3 +460,25 @@ meta_screen_hide_tip (MetaScreen *screen)
screen->showing_tooltip = FALSE;
}
}
+
+int
+meta_screen_get_n_workspaces (MetaScreen *screen)
+{
+ GList *tmp;
+ int i;
+
+ i = 0;
+ tmp = screen->display->workspaces;
+ while (tmp != NULL)
+ {
+ MetaWorkspace *w = tmp->data;
+
+ if (w->screen == screen)
+ ++i;
+
+ tmp = tmp->next;
+ }
+
+ return i;
+
+}
diff --git a/src/screen.h b/src/screen.h
index 50647915..398ca158 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -77,6 +77,9 @@ void meta_screen_show_tip (MetaScreen *scree
const char *markup);
void meta_screen_hide_tip (MetaScreen *screen);
+int meta_screen_get_n_workspaces (MetaScreen *screen);
+
+
#endif
diff --git a/src/uislave/menu.c b/src/uislave/menu.c
index 81015dd6..5e77abc9 100644
--- a/src/uislave/menu.c
+++ b/src/uislave/menu.c
@@ -22,6 +22,7 @@
#include "menu.h"
#include "main.h"
#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
typedef struct _MenuItem MenuItem;
typedef struct _MenuData MenuData;
@@ -44,9 +45,10 @@ static void activate_cb (GtkWidget *menuitem, gpointer data);
static GtkWidget *menu = NULL;
static MenuItem menuitems[] = {
- { META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("Close") },
- { META_MESSAGE_MENU_MINIMIZE, NULL, N_("Minimize") },
- { META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Maximize") }
+ { META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("_Close") },
+ { META_MESSAGE_MENU_MINIMIZE, NULL, N_("_Minimize") },
+ { META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Ma_ximize") },
+ { META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }
};
static void
@@ -71,6 +73,67 @@ popup_position_func (GtkMenu *menu,
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
}
+static gint
+get_num_desktops (void)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *num;
+ int result;
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ gdk_atom_intern ("_NET_NUMBER_OF_DESKTOPS", FALSE),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&num);
+
+ if (type != XA_CARDINAL)
+ return 0;
+
+ result = *num;
+
+ XFree (num);
+
+ return result;
+}
+
+static gulong
+get_current_desktop (GdkWindow *window)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *num;
+ gulong result;
+ int err;
+
+ gdk_error_trap_push ();
+ type = None;
+ XGetWindowProperty (gdk_display, GDK_WINDOW_XID (window),
+ gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&num);
+ err = gdk_error_trap_pop ();
+ if (err != Success)
+ meta_ui_warning ("Error %d getting _NET_WM_DESKTOP\n", err);
+
+ if (type != XA_CARDINAL)
+ {
+ meta_ui_warning ("_NET_WM_DESKTOP has wrong type %s\n", gdk_atom_name (type));
+ return -1;
+ }
+
+ result = *num;
+
+ XFree (num);
+
+ return result;
+}
+
void
meta_window_menu_show (gulong xwindow,
int root_x, int root_y,
@@ -82,6 +145,8 @@ meta_window_menu_show (gulong xwindow,
int i;
GdkWindow *window;
GdkPoint *pt;
+ int n_workspaces;
+ int current_workspace;
if (menu)
gtk_widget_destroy (menu);
@@ -110,7 +175,7 @@ meta_window_menu_show (gulong xwindow,
{
GtkWidget *image;
- mi = gtk_image_menu_item_new_with_label (menuitems[i].label);
+ mi = gtk_image_menu_item_new_with_mnemonic (menuitems[i].label);
image = gtk_image_new_from_stock (menuitems[i].stock_id,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
@@ -119,7 +184,7 @@ meta_window_menu_show (gulong xwindow,
}
else
{
- mi = gtk_menu_item_new_with_label (menuitems[i].label);
+ mi = gtk_menu_item_new_with_mnemonic (menuitems[i].label);
}
if (insensitive & menuitems[i].op)
@@ -142,6 +207,60 @@ meta_window_menu_show (gulong xwindow,
}
++i;
}
+
+ if (ops & META_MESSAGE_MENU_WORKSPACES)
+ {
+ n_workspaces = get_num_desktops ();
+ current_workspace = get_current_desktop (window);
+
+ meta_ui_warning ("Creating %d workspace menu current %d\n",
+ n_workspaces, current_workspace);
+
+ if (n_workspaces > 0 && current_workspace >= 0)
+ {
+ i = 0;
+ while (i < n_workspaces)
+ {
+ char *label;
+ GtkWidget *mi;
+ MenuData *md;
+
+ label = g_strdup_printf (_("Move to workspace _%d\n"),
+ i + 1);
+
+ mi = gtk_menu_item_new_with_mnemonic (label);
+
+ g_free (label);
+
+ if (current_workspace == i ||
+ insensitive & META_MESSAGE_MENU_WORKSPACES)
+ gtk_widget_set_sensitive (mi, FALSE);
+
+ md = g_new (MenuData, 1);
+
+ md->window = window;
+ md->op = META_MESSAGE_MENU_WORKSPACES;
+
+ g_object_set_data (G_OBJECT (mi),
+ "workspace",
+ GINT_TO_POINTER (i));
+
+ gtk_signal_connect (GTK_OBJECT (mi),
+ "activate",
+ GTK_SIGNAL_FUNC (activate_cb),
+ md);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ mi);
+
+ gtk_widget_show (mi);
+
+ ++i;
+ }
+ }
+ }
+ else
+ meta_ui_warning ("not creating workspace menu\n");
gtk_signal_connect (GTK_OBJECT (menu),
"destroy",
@@ -197,6 +316,58 @@ close_window (GdkWindow *window)
}
static void
+wmspec_change_state (gboolean add,
+ GdkWindow *window,
+ GdkAtom state1,
+ GdkAtom state2)
+{
+ XEvent xev;
+ Atom op;
+
+ if (add)
+ op = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE);
+ else
+ op = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = op;
+ xev.xclient.data.l[1] = state1;
+ xev.xclient.data.l[2] = state2;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
+wmspec_change_desktop (GdkWindow *window,
+ gint desktop)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = desktop;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
activate_cb (GtkWidget *menuitem, gpointer data)
{
MenuData *md;
@@ -219,6 +390,23 @@ activate_cb (GtkWidget *menuitem, gpointer data)
gdk_error_trap_pop ();
break;
+ case META_MESSAGE_MENU_SHADE:
+ wmspec_change_state (TRUE, md->window,
+ gdk_atom_intern ("_NET_WM_STATE_SHADED", FALSE),
+ 0);
+ break;
+
+ case META_MESSAGE_MENU_WORKSPACES:
+ {
+ int workspace;
+
+ workspace = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
+ "workspace"));
+
+ wmspec_change_desktop (md->window, workspace);
+ }
+ break;
+
default:
meta_ui_warning (G_STRLOC": Unknown window op\n");
break;
diff --git a/src/uislave/messages.h b/src/uislave/messages.h
index 4e083042..c4fe64c0 100644
--- a/src/uislave/messages.h
+++ b/src/uislave/messages.h
@@ -133,7 +133,13 @@ typedef enum
META_MESSAGE_MENU_DELETE = 1 << 0,
META_MESSAGE_MENU_MINIMIZE = 1 << 1,
META_MESSAGE_MENU_MAXIMIZE = 1 << 2,
- META_MESSAGE_MENU_ALL = META_MESSAGE_MENU_DELETE | META_MESSAGE_MENU_MINIMIZE | META_MESSAGE_MENU_MAXIMIZE
+ META_MESSAGE_MENU_SHADE = 1 << 3,
+ META_MESSAGE_MENU_WORKSPACES = 1 << 4,
+ META_MESSAGE_MENU_ALL = META_MESSAGE_MENU_DELETE |
+ META_MESSAGE_MENU_MINIMIZE |
+ META_MESSAGE_MENU_MAXIMIZE |
+ META_MESSAGE_MENU_SHADE |
+ META_MESSAGE_MENU_WORKSPACES
} MetaMessageWindowMenuOps;
struct _MetaMessageShowWindowMenu
diff --git a/src/window.c b/src/window.c
index a0673049..f0ed4dd0 100644
--- a/src/window.c
+++ b/src/window.c
@@ -620,6 +620,33 @@ meta_window_focus (MetaWindow *window,
}
void
+meta_window_change_workspace (MetaWindow *window,
+ MetaWorkspace *workspace)
+{
+ meta_verbose ("Changing window %s to workspace %d\n",
+ window->desc, meta_workspace_index (workspace));
+
+ /* See if we're already on this space */
+ if (g_list_find (window->workspaces, workspace) != NULL)
+ {
+ meta_verbose ("Already on this workspace\n");
+ return;
+ }
+
+ /* Add first, to maintain invariant that we're always
+ * on some workspace.
+ */
+ meta_workspace_add_window (workspace, window);
+
+ /* Lamely rely on prepend */
+ g_assert (window->workspaces->data == workspace);
+
+ /* Remove from all other spaces */
+ while (window->workspaces->next) /* while list size > 1 */
+ meta_workspace_remove_window (window->workspaces->next->data, window);
+}
+
+void
meta_window_raise (MetaWindow *window)
{
meta_verbose ("Raising window %s\n", window->desc);
diff --git a/src/window.h b/src/window.h
index bd3bf270..36a27ad1 100644
--- a/src/window.h
+++ b/src/window.h
@@ -112,7 +112,8 @@ void meta_window_maximize (MetaWindow *window);
void meta_window_unmaximize (MetaWindow *window);
void meta_window_shade (MetaWindow *window);
void meta_window_unshade (MetaWindow *window);
-
+void meta_window_change_workspace (MetaWindow *window,
+ MetaWorkspace *workspace);
/* args to move are window pos, not frame pos */
void meta_window_move (MetaWindow *window,
diff --git a/src/workspace.c b/src/workspace.c
index 2e1fb53d..3920c77b 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -20,9 +20,14 @@
*/
#include "workspace.h"
+#include "errors.h"
+#include <X11/Xatom.h>
void meta_workspace_queue_calc_showing (MetaWorkspace *workspace);
+static int set_current_workspace_hint (MetaWindow *window);
+static int set_number_of_spaces_hint (MetaScreen *screen);
+
MetaWorkspace*
meta_workspace_new (MetaScreen *screen)
{
@@ -42,6 +47,9 @@ meta_workspace_new (MetaScreen *screen)
workspace->workarea.y = 0;
workspace->workarea.width = WidthOfScreen (screen->xscreen);
workspace->workarea.height = HeightOfScreen (screen->xscreen);
+
+ /* Update hint for current number of workspaces */
+ set_number_of_spaces_hint (screen);
return workspace;
}
@@ -79,6 +87,8 @@ meta_workspace_add_window (MetaWorkspace *workspace,
workspace->windows = g_list_prepend (workspace->windows, window);
window->workspaces = g_list_prepend (window->workspaces, workspace);
+ set_current_workspace_hint (window);
+
meta_window_queue_calc_showing (window);
}
@@ -91,6 +101,8 @@ meta_workspace_remove_window (MetaWorkspace *workspace,
workspace->windows = g_list_remove (workspace->windows, window);
window->workspaces = g_list_remove (window->workspaces, workspace);
+ set_current_workspace_hint (window);
+
meta_window_queue_calc_showing (window);
}
@@ -147,3 +159,70 @@ meta_workspace_index (MetaWorkspace *workspace)
meta_bug ("Workspace does not exist to index!\n");
}
+
+int
+meta_workspace_screen_index (MetaWorkspace *workspace)
+{
+ GList *tmp;
+ int i;
+
+ i = 0;
+ tmp = workspace->screen->display->workspaces;
+ while (tmp != NULL)
+ {
+ MetaWorkspace *w = tmp->data;
+
+ if (tmp->data == workspace)
+ return i;
+
+ if (w->screen == workspace->screen)
+ ++i;
+
+ tmp = tmp->next;
+ }
+
+ meta_bug ("Workspace does not exist to index!\n");
+}
+
+
+static int
+set_current_workspace_hint (MetaWindow *window)
+{
+ /* if on more than one workspace, we claim to be "sticky" */
+ unsigned long data[1];
+
+ if (window->workspaces == NULL)
+ return Success; /* this happens when destroying windows */
+
+ if (g_list_length (window->workspaces) > 1)
+ data[0] = 0xFFFFFFFF;
+ else
+ data[0] = meta_workspace_screen_index (window->workspaces->data);
+
+ meta_verbose ("Setting _NET_WM_DESKTOP of %s to %ld\n",
+ window->desc, data[0]);
+
+ meta_error_trap_push (window->display);
+ XChangeProperty (window->display->xdisplay, window->xwindow,
+ window->display->atom_net_wm_desktop,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) data, 1);
+ return meta_error_trap_pop (window->display);
+}
+
+static int
+set_number_of_spaces_hint (MetaScreen *screen)
+{
+ unsigned long data[1];
+
+ data[0] = meta_screen_get_n_workspaces (screen);
+
+ meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %ld\n", data[0]);
+
+ meta_error_trap_push (screen->display);
+ XChangeProperty (screen->display->xdisplay, screen->xroot,
+ screen->display->atom_net_number_of_desktops,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) data, 1);
+ return meta_error_trap_pop (screen->display);
+}
diff --git a/src/workspace.h b/src/workspace.h
index 5cde8a0a..d7f7e36d 100644
--- a/src/workspace.h
+++ b/src/workspace.h
@@ -42,6 +42,7 @@ void meta_workspace_remove_window (MetaWorkspace *workspace,
void meta_workspace_activate (MetaWorkspace *workspace);
int meta_workspace_index (MetaWorkspace *workspace);
+int meta_workspace_screen_index (MetaWorkspace *workspace);
#endif