mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
workspace menu
This commit is contained in:
parent
6631763c96
commit
d0f6283cf5
@ -84,7 +84,9 @@ meta_display_open (const char *name)
|
|||||||
"MOTIF_WM_HINTS",
|
"MOTIF_WM_HINTS",
|
||||||
"_NET_WM_STATE_SHADED",
|
"_NET_WM_STATE_SHADED",
|
||||||
"_NET_WM_STATE_MAXIMIZED_HORZ",
|
"_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)];
|
Atom atoms[G_N_ELEMENTS(atom_names)];
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ meta_display_open (const char *name)
|
|||||||
display->name = g_strdup (XDisplayName (name));
|
display->name = g_strdup (XDisplayName (name));
|
||||||
display->xdisplay = xdisplay;
|
display->xdisplay = xdisplay;
|
||||||
display->error_traps = NULL;
|
display->error_traps = NULL;
|
||||||
|
display->server_grab_count = 0;
|
||||||
display->workspaces = NULL;
|
display->workspaces = NULL;
|
||||||
|
|
||||||
/* we have to go ahead and do this so error handlers work */
|
/* we have to go ahead and do this so error handlers work */
|
||||||
@ -119,6 +121,22 @@ meta_display_open (const char *name)
|
|||||||
|
|
||||||
meta_display_init_keys (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;
|
screens = NULL;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < ScreenCount (xdisplay))
|
while (i < ScreenCount (xdisplay))
|
||||||
@ -152,22 +170,6 @@ meta_display_open (const char *name)
|
|||||||
|
|
||||||
display->window_ids = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
|
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->double_click_time = 250;
|
||||||
display->last_button_time = 0;
|
display->last_button_time = 0;
|
||||||
display->last_button_xwindow = None;
|
display->last_button_xwindow = None;
|
||||||
@ -551,6 +553,27 @@ event_queue_callback (MetaEventQueue *queue,
|
|||||||
*/
|
*/
|
||||||
meta_window_delete (window, CurrentTime);
|
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;
|
break;
|
||||||
case MappingNotify:
|
case MappingNotify:
|
||||||
|
@ -50,6 +50,8 @@ struct _MetaDisplay
|
|||||||
Atom atom_net_wm_state_shaded;
|
Atom atom_net_wm_state_shaded;
|
||||||
Atom atom_net_wm_state_maximized_horz;
|
Atom atom_net_wm_state_maximized_horz;
|
||||||
Atom atom_net_wm_state_maximized_vert;
|
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,
|
/* This is the actual window from focus events,
|
||||||
* not the one we last set
|
* not the one we last set
|
||||||
@ -106,5 +108,4 @@ MetaWorkspace* meta_display_get_workspace_by_screen_index (MetaDisplay *displa
|
|||||||
MetaScreen *screen,
|
MetaScreen *screen,
|
||||||
int index);
|
int index);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
198
src/menu.c
198
src/menu.c
@ -22,6 +22,7 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
typedef struct _MenuItem MenuItem;
|
typedef struct _MenuItem MenuItem;
|
||||||
typedef struct _MenuData MenuData;
|
typedef struct _MenuData MenuData;
|
||||||
@ -44,9 +45,10 @@ static void activate_cb (GtkWidget *menuitem, gpointer data);
|
|||||||
|
|
||||||
static GtkWidget *menu = NULL;
|
static GtkWidget *menu = NULL;
|
||||||
static MenuItem menuitems[] = {
|
static MenuItem menuitems[] = {
|
||||||
{ META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("Close") },
|
{ META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("_Close") },
|
||||||
{ META_MESSAGE_MENU_MINIMIZE, NULL, N_("Minimize") },
|
{ META_MESSAGE_MENU_MINIMIZE, NULL, N_("_Minimize") },
|
||||||
{ META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Maximize") }
|
{ META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Ma_ximize") },
|
||||||
|
{ META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -71,6 +73,67 @@ popup_position_func (GtkMenu *menu,
|
|||||||
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
|
*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
|
void
|
||||||
meta_window_menu_show (gulong xwindow,
|
meta_window_menu_show (gulong xwindow,
|
||||||
int root_x, int root_y,
|
int root_x, int root_y,
|
||||||
@ -82,6 +145,8 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
int i;
|
int i;
|
||||||
GdkWindow *window;
|
GdkWindow *window;
|
||||||
GdkPoint *pt;
|
GdkPoint *pt;
|
||||||
|
int n_workspaces;
|
||||||
|
int current_workspace;
|
||||||
|
|
||||||
if (menu)
|
if (menu)
|
||||||
gtk_widget_destroy (menu);
|
gtk_widget_destroy (menu);
|
||||||
@ -110,7 +175,7 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
{
|
{
|
||||||
GtkWidget *image;
|
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,
|
image = gtk_image_new_from_stock (menuitems[i].stock_id,
|
||||||
GTK_ICON_SIZE_MENU);
|
GTK_ICON_SIZE_MENU);
|
||||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
|
||||||
@ -119,7 +184,7 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
}
|
}
|
||||||
else
|
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)
|
if (insensitive & menuitems[i].op)
|
||||||
@ -143,6 +208,60 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
++i;
|
++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),
|
gtk_signal_connect (GTK_OBJECT (menu),
|
||||||
"destroy",
|
"destroy",
|
||||||
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
||||||
@ -196,6 +315,58 @@ close_window (GdkWindow *window)
|
|||||||
gdk_error_trap_pop ();
|
gdk_error_trap_pop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
activate_cb (GtkWidget *menuitem, gpointer data)
|
activate_cb (GtkWidget *menuitem, gpointer data)
|
||||||
{
|
{
|
||||||
@ -219,6 +390,23 @@ activate_cb (GtkWidget *menuitem, gpointer data)
|
|||||||
gdk_error_trap_pop ();
|
gdk_error_trap_pop ();
|
||||||
break;
|
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:
|
default:
|
||||||
meta_ui_warning (G_STRLOC": Unknown window op\n");
|
meta_ui_warning (G_STRLOC": Unknown window op\n");
|
||||||
break;
|
break;
|
||||||
|
22
src/screen.c
22
src/screen.c
@ -460,3 +460,25 @@ meta_screen_hide_tip (MetaScreen *screen)
|
|||||||
screen->showing_tooltip = FALSE;
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -77,6 +77,9 @@ void meta_screen_show_tip (MetaScreen *scree
|
|||||||
const char *markup);
|
const char *markup);
|
||||||
void meta_screen_hide_tip (MetaScreen *screen);
|
void meta_screen_hide_tip (MetaScreen *screen);
|
||||||
|
|
||||||
|
int meta_screen_get_n_workspaces (MetaScreen *screen);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
typedef struct _MenuItem MenuItem;
|
typedef struct _MenuItem MenuItem;
|
||||||
typedef struct _MenuData MenuData;
|
typedef struct _MenuData MenuData;
|
||||||
@ -44,9 +45,10 @@ static void activate_cb (GtkWidget *menuitem, gpointer data);
|
|||||||
|
|
||||||
static GtkWidget *menu = NULL;
|
static GtkWidget *menu = NULL;
|
||||||
static MenuItem menuitems[] = {
|
static MenuItem menuitems[] = {
|
||||||
{ META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("Close") },
|
{ META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("_Close") },
|
||||||
{ META_MESSAGE_MENU_MINIMIZE, NULL, N_("Minimize") },
|
{ META_MESSAGE_MENU_MINIMIZE, NULL, N_("_Minimize") },
|
||||||
{ META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Maximize") }
|
{ META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Ma_ximize") },
|
||||||
|
{ META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -71,6 +73,67 @@ popup_position_func (GtkMenu *menu,
|
|||||||
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
|
*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
|
void
|
||||||
meta_window_menu_show (gulong xwindow,
|
meta_window_menu_show (gulong xwindow,
|
||||||
int root_x, int root_y,
|
int root_x, int root_y,
|
||||||
@ -82,6 +145,8 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
int i;
|
int i;
|
||||||
GdkWindow *window;
|
GdkWindow *window;
|
||||||
GdkPoint *pt;
|
GdkPoint *pt;
|
||||||
|
int n_workspaces;
|
||||||
|
int current_workspace;
|
||||||
|
|
||||||
if (menu)
|
if (menu)
|
||||||
gtk_widget_destroy (menu);
|
gtk_widget_destroy (menu);
|
||||||
@ -110,7 +175,7 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
{
|
{
|
||||||
GtkWidget *image;
|
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,
|
image = gtk_image_new_from_stock (menuitems[i].stock_id,
|
||||||
GTK_ICON_SIZE_MENU);
|
GTK_ICON_SIZE_MENU);
|
||||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
|
||||||
@ -119,7 +184,7 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
}
|
}
|
||||||
else
|
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)
|
if (insensitive & menuitems[i].op)
|
||||||
@ -143,6 +208,60 @@ meta_window_menu_show (gulong xwindow,
|
|||||||
++i;
|
++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),
|
gtk_signal_connect (GTK_OBJECT (menu),
|
||||||
"destroy",
|
"destroy",
|
||||||
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
||||||
@ -196,6 +315,58 @@ close_window (GdkWindow *window)
|
|||||||
gdk_error_trap_pop ();
|
gdk_error_trap_pop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
activate_cb (GtkWidget *menuitem, gpointer data)
|
activate_cb (GtkWidget *menuitem, gpointer data)
|
||||||
{
|
{
|
||||||
@ -219,6 +390,23 @@ activate_cb (GtkWidget *menuitem, gpointer data)
|
|||||||
gdk_error_trap_pop ();
|
gdk_error_trap_pop ();
|
||||||
break;
|
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:
|
default:
|
||||||
meta_ui_warning (G_STRLOC": Unknown window op\n");
|
meta_ui_warning (G_STRLOC": Unknown window op\n");
|
||||||
break;
|
break;
|
||||||
|
@ -133,7 +133,13 @@ typedef enum
|
|||||||
META_MESSAGE_MENU_DELETE = 1 << 0,
|
META_MESSAGE_MENU_DELETE = 1 << 0,
|
||||||
META_MESSAGE_MENU_MINIMIZE = 1 << 1,
|
META_MESSAGE_MENU_MINIMIZE = 1 << 1,
|
||||||
META_MESSAGE_MENU_MAXIMIZE = 1 << 2,
|
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;
|
} MetaMessageWindowMenuOps;
|
||||||
|
|
||||||
struct _MetaMessageShowWindowMenu
|
struct _MetaMessageShowWindowMenu
|
||||||
|
27
src/window.c
27
src/window.c
@ -619,6 +619,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
|
void
|
||||||
meta_window_raise (MetaWindow *window)
|
meta_window_raise (MetaWindow *window)
|
||||||
{
|
{
|
||||||
|
@ -112,7 +112,8 @@ void meta_window_maximize (MetaWindow *window);
|
|||||||
void meta_window_unmaximize (MetaWindow *window);
|
void meta_window_unmaximize (MetaWindow *window);
|
||||||
void meta_window_shade (MetaWindow *window);
|
void meta_window_shade (MetaWindow *window);
|
||||||
void meta_window_unshade (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 */
|
/* args to move are window pos, not frame pos */
|
||||||
void meta_window_move (MetaWindow *window,
|
void meta_window_move (MetaWindow *window,
|
||||||
|
@ -20,9 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
void meta_workspace_queue_calc_showing (MetaWorkspace *workspace);
|
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*
|
MetaWorkspace*
|
||||||
meta_workspace_new (MetaScreen *screen)
|
meta_workspace_new (MetaScreen *screen)
|
||||||
{
|
{
|
||||||
@ -43,6 +48,9 @@ meta_workspace_new (MetaScreen *screen)
|
|||||||
workspace->workarea.width = WidthOfScreen (screen->xscreen);
|
workspace->workarea.width = WidthOfScreen (screen->xscreen);
|
||||||
workspace->workarea.height = HeightOfScreen (screen->xscreen);
|
workspace->workarea.height = HeightOfScreen (screen->xscreen);
|
||||||
|
|
||||||
|
/* Update hint for current number of workspaces */
|
||||||
|
set_number_of_spaces_hint (screen);
|
||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +87,8 @@ meta_workspace_add_window (MetaWorkspace *workspace,
|
|||||||
workspace->windows = g_list_prepend (workspace->windows, window);
|
workspace->windows = g_list_prepend (workspace->windows, window);
|
||||||
window->workspaces = g_list_prepend (window->workspaces, workspace);
|
window->workspaces = g_list_prepend (window->workspaces, workspace);
|
||||||
|
|
||||||
|
set_current_workspace_hint (window);
|
||||||
|
|
||||||
meta_window_queue_calc_showing (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);
|
workspace->windows = g_list_remove (workspace->windows, window);
|
||||||
window->workspaces = g_list_remove (window->workspaces, workspace);
|
window->workspaces = g_list_remove (window->workspaces, workspace);
|
||||||
|
|
||||||
|
set_current_workspace_hint (window);
|
||||||
|
|
||||||
meta_window_queue_calc_showing (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");
|
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);
|
||||||
|
}
|
||||||
|
@ -42,6 +42,7 @@ void meta_workspace_remove_window (MetaWorkspace *workspace,
|
|||||||
|
|
||||||
void meta_workspace_activate (MetaWorkspace *workspace);
|
void meta_workspace_activate (MetaWorkspace *workspace);
|
||||||
int meta_workspace_index (MetaWorkspace *workspace);
|
int meta_workspace_index (MetaWorkspace *workspace);
|
||||||
|
int meta_workspace_screen_index (MetaWorkspace *workspace);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user