This commit is contained in:
rhp 2001-06-23 05:49:35 +00:00
parent 7ecf21af70
commit bf64e719a1
18 changed files with 624 additions and 231 deletions

View File

@ -24,6 +24,7 @@
/* Don't include GTK or core headers here */
#include <X11/Xlib.h>
#include <glib.h>
typedef enum
{
@ -39,4 +40,26 @@ typedef enum
META_FRAME_MAXIMIZED = 1 << 9
} MetaFrameFlags;
typedef enum
{
META_MENU_OP_DELETE = 1 << 0,
META_MENU_OP_MINIMIZE = 1 << 1,
META_MENU_OP_UNMAXIMIZE = 1 << 2,
META_MENU_OP_MAXIMIZE = 1 << 3,
META_MENU_OP_UNSHADE = 1 << 4,
META_MENU_OP_SHADE = 1 << 5,
META_MENU_OP_UNSTICK = 1 << 6,
META_MENU_OP_STICK = 1 << 7,
META_MENU_OP_WORKSPACES = 1 << 8
} MetaMenuOp;
typedef struct _MetaWindowMenu MetaWindowMenu;
typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
Display *xdisplay,
Window client_xwindow,
MetaMenuOp op,
int workspace,
gpointer data);
#endif

View File

@ -355,4 +355,24 @@ meta_core_get_frame_workspace (Display *xdisplay,
return meta_window_get_net_wm_desktop (window);
}
void
meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,
int root_x,
int root_y,
int button,
Time timestamp)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, frame_xwindow);
if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
meta_window_show_menu (window, root_x, root_y, button, timestamp);
}

View File

@ -91,6 +91,13 @@ int meta_core_get_frame_workspace (Display *xdisplay,
Window frame_xwindow);
void meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,
int root_x,
int root_y,
int button,
Time timestamp);
#endif

View File

@ -125,7 +125,9 @@ meta_display_open (const char *name)
"_NET_WM_STATE_SKIP_TASKBAR",
"_NET_WM_STATE_SKIP_PAGER",
"_WIN_WORKSPACE",
"_WIN_LAYER"
"_WIN_LAYER",
"_WIN_PROTOCOLS",
"_WIN_SUPPORTING_WM_CHECK"
};
Atom atoms[G_N_ELEMENTS(atom_names)];
@ -200,6 +202,8 @@ meta_display_open (const char *name)
display->atom_net_wm_state_skip_pager = atoms[31];
display->atom_win_workspace = atoms[32];
display->atom_win_layer = atoms[33];
display->atom_win_protocols = atoms[34];
display->atom_win_supporting_wm_check = atoms[35];
/* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
* created in screen_new
@ -268,7 +272,7 @@ meta_display_open (const char *name)
set_string_hint (display,
display->leader_window,
display->atom_net_supporting_wm_check,
display->atom_net_wm_name,
"Metacity");
/* Now manage all existing windows */

View File

@ -90,6 +90,8 @@ struct _MetaDisplay
Atom atom_net_wm_state_skip_pager;
Atom atom_win_workspace;
Atom atom_win_layer;
Atom atom_win_protocols;
Atom atom_win_supporting_wm_check;
/* This is the actual window from focus events,
* not the one we last set

View File

@ -27,7 +27,8 @@
ExposureMask | \
ButtonPressMask | ButtonReleaseMask | \
PointerMotionMask | PointerMotionHintMask | \
EnterWindowMask | LeaveWindowMask)
EnterWindowMask | LeaveWindowMask | \
FocusChangeMask)
void
meta_window_ensure_frame (MetaWindow *window)
@ -106,6 +107,9 @@ meta_window_ensure_frame (MetaWindow *window)
meta_ui_set_frame_title (window->screen->ui,
window->frame->xwindow,
window->title);
/* Move keybindings to frame instead of window */
meta_window_grab_keys (window);
}
void
@ -142,6 +146,9 @@ meta_window_destroy_frame (MetaWindow *window)
window->frame = NULL;
/* Move keybindings to window instead of frame */
meta_window_grab_keys (window);
/* should we push an error trap? */
XDestroyWindow (window->display->xdisplay, frame->xwindow);
@ -270,6 +277,8 @@ meta_frame_event (MetaFrame *frame,
switch (event->type)
{
case KeyPress:
meta_display_process_key_press (frame->window->display,
frame->window, event);
break;
case KeyRelease:
break;
@ -290,8 +299,9 @@ meta_frame_event (MetaFrame *frame,
case LeaveNotify:
break;
case FocusIn:
break;
case FocusOut:
meta_window_notify_focus (frame->window,
event);
break;
case KeymapNotify:
break;

View File

@ -301,9 +301,6 @@ meta_frames_destroy (GtkObject *object)
frames = META_FRAMES (object);
if (frames->menu)
gtk_widget_destroy (frames->menu);
winlist = NULL;
g_hash_table_foreach (frames->frames,
listify_func,
@ -857,12 +854,6 @@ meta_frames_end_grab (MetaFrames *frames,
{
if (frames->grab_frame)
{
if (frames->grab_status == META_FRAME_STATUS_CLICKING_MENU)
{
if (frames->menu)
gtk_widget_destroy (frames->menu);
}
frames->grab_frame = NULL;
frames->grab_status = META_FRAME_STATUS_NORMAL;
gdk_pointer_ungrab (timestamp);
@ -1030,7 +1021,8 @@ meta_frames_button_press_event (GtkWidget *widget,
if (status == META_FRAME_STATUS_CLICKING_MENU)
{
meta_window_menu_show (frames, frame,
meta_core_show_window_menu (gdk_display,
frame->xwindow,
event->x_root,
event->y_root,
event->button,

View File

@ -90,8 +90,6 @@ struct _MetaFrames
GHashTable *frames;
GtkWidget *menu;
/* The below is all for grabs */
MetaFrameStatus grab_status;
MetaUIFrame *grab_frame;
@ -136,6 +134,7 @@ void meta_frames_get_pixmap_for_control (MetaFrames *frames,
MetaFrameControl control,
GdkPixmap **pixmap,
GdkBitmap **mask);
void meta_frames_notify_menu_hide (MetaFrames *frames);
#endif

View File

@ -22,6 +22,8 @@
#include "keybindings.h"
#include "workspace.h"
#include "errors.h"
#include "ui.h"
#include "frame.h"
#include <X11/keysym.h>
@ -30,10 +32,16 @@
*/
typedef void (* MetaKeyHandler) (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data);
static void handle_activate_workspace (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data);
static void handle_activate_menu (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data);
@ -50,7 +58,7 @@ struct _MetaKeyBinding
#define INTERESTING_MODIFIERS (ShiftMask | ControlMask | Mod1Mask)
static MetaKeyBinding bindings[] = {
static MetaKeyBinding screen_bindings[] = {
{ XK_F1, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (0), 0 },
{ XK_F2, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (1), 0 },
{ XK_F3, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (2), 0 },
@ -62,16 +70,23 @@ static MetaKeyBinding bindings[] = {
{ XK_3, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (2), 0 },
{ XK_4, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (3), 0 },
{ XK_5, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (4), 0 },
{ XK_6, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (5), 0 }
{ XK_6, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (5), 0 },
{ None, 0, NULL, NULL, 0 }
};
void
meta_display_init_keys (MetaDisplay *display)
static MetaKeyBinding window_bindings[] = {
{ XK_space, Mod1Mask, handle_activate_menu, NULL, 0 },
{ None, 0, NULL, NULL, 0 }
};
static void
init_bindings (MetaDisplay *display,
MetaKeyBinding *bindings)
{
int i;
i = 0;
while (i < G_N_ELEMENTS (bindings))
while (bindings[i].keysym != None)
{
bindings[i].keycode = XKeysymToKeycode (display->xdisplay,
bindings[i].keysym);
@ -81,22 +96,31 @@ meta_display_init_keys (MetaDisplay *display)
}
void
meta_screen_grab_keys (MetaScreen *screen)
meta_display_init_keys (MetaDisplay *display)
{
init_bindings (display, screen_bindings);
init_bindings (display, window_bindings);
}
static void
grab_keys (MetaKeyBinding *bindings,
MetaDisplay *display,
Window xwindow)
{
int i;
i = 0;
while (i < G_N_ELEMENTS (bindings))
while (bindings[i].keysym != None)
{
if (bindings[i].keycode != 0)
{
int result;
meta_error_trap_push (screen->display);
XGrabKey (screen->display->xdisplay, bindings[i].keycode,
bindings[i].mask, screen->xroot, True,
meta_error_trap_push (display);
XGrabKey (display->xdisplay, bindings[i].keycode,
bindings[i].mask, xwindow, True,
GrabModeAsync, GrabModeAsync);
result = meta_error_trap_pop (screen->display);
result = meta_error_trap_pop (display);
if (result != Success)
{
const char *name;
@ -107,8 +131,6 @@ meta_screen_grab_keys (MetaScreen *screen)
if (result == BadAccess)
meta_warning (_("Some other program is already using the key %s as a binding\n"), name);
else
meta_bug ("Unexpected error setting up keybindings\n");
}
}
@ -116,26 +138,81 @@ meta_screen_grab_keys (MetaScreen *screen)
}
}
static void
ungrab_keys (MetaKeyBinding *bindings,
MetaDisplay *display,
Window xwindow)
{
int i;
i = 0;
while (bindings[i].keysym != None)
{
if (bindings[i].keycode != 0)
{
meta_error_trap_push (display);
XUngrabKey (display->xdisplay, bindings[i].keycode,
bindings[i].mask, xwindow);
meta_error_trap_pop (display);
}
++i;
}
}
void
meta_screen_grab_keys (MetaScreen *screen)
{
grab_keys (screen_bindings, screen->display, screen->xroot);
}
void
meta_screen_ungrab_keys (MetaScreen *screen)
{
int i;
i = 0;
while (i < G_N_ELEMENTS (bindings))
{
if (bindings[i].keycode != 0)
{
XUngrabKey (screen->display->xdisplay, bindings[i].keycode,
bindings[i].mask, screen->xroot);
}
++i;
}
ungrab_keys (screen_bindings, screen->display, screen->xroot);
}
void
meta_display_process_key_press (MetaDisplay *display,
meta_window_grab_keys (MetaWindow *window)
{
if (window->keys_grabbed)
{
if (window->frame && !window->grab_on_frame)
ungrab_keys (window_bindings, window->display,
window->xwindow);
else if (window->frame == NULL &&
window->grab_on_frame)
; /* continue to regrab on client window */
else
return; /* already all good */
}
grab_keys (window_bindings, window->display,
window->frame ? window->frame->xwindow : window->xwindow);
window->keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
}
void
meta_window_ungrab_keys (MetaWindow *window)
{
if (window->keys_grabbed)
{
if (window->grab_on_frame &&
window->frame != NULL)
ungrab_keys (window_bindings, window->display,
window->frame->xwindow);
else if (!window->grab_on_frame)
ungrab_keys (window_bindings, window->display,
window->xwindow);
}
}
static void
process_event (MetaKeyBinding *bindings,
MetaDisplay *display,
MetaWindow *window,
XEvent *event)
{
KeySym keysym;
@ -144,13 +221,13 @@ meta_display_process_key_press (MetaDisplay *display,
keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0);
i = 0;
while (i < G_N_ELEMENTS (bindings))
while (bindings[i].keysym != None)
{
if (bindings[i].keysym == keysym &&
((event->xkey.state & INTERESTING_MODIFIERS) ==
bindings[i].mask))
{
(* bindings[i].handler) (display, event, bindings[i].data);
(* bindings[i].handler) (display, window, event, bindings[i].data);
break;
}
@ -158,8 +235,18 @@ meta_display_process_key_press (MetaDisplay *display,
}
}
void
meta_display_process_key_press (MetaDisplay *display,
MetaWindow *window,
XEvent *event)
{
process_event (screen_bindings, display, window, event);
process_event (window_bindings, display, window, event);
}
static void
handle_activate_workspace (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data)
{
@ -180,3 +267,22 @@ handle_activate_workspace (MetaDisplay *display,
}
}
static void
handle_activate_menu (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data)
{
if (display->focus_window)
{
int x, y;
meta_window_get_position (display->focus_window,
&x, &y);
meta_window_show_menu (display->focus_window,
x, y,
0,
event->xkey.time);
}
}

View File

@ -23,11 +23,15 @@
#define META_KEYBINDINGS_H
#include "display.h"
#include "window.h"
void meta_display_init_keys (MetaDisplay *display);
void meta_screen_grab_keys (MetaScreen *screen);
void meta_screen_ungrab_keys (MetaScreen *screen);
void meta_window_grab_keys (MetaWindow *window);
void meta_window_ungrab_keys (MetaWindow *window);
void meta_display_process_key_press (MetaDisplay *display,
MetaWindow *window,
XEvent *event);
#endif

View File

@ -27,19 +27,6 @@
typedef struct _MenuItem MenuItem;
typedef struct _MenuData MenuData;
typedef enum
{
META_MENU_OP_DELETE = 1 << 0,
META_MENU_OP_MINIMIZE = 1 << 1,
META_MENU_OP_UNMAXIMIZE = 1 << 2,
META_MENU_OP_MAXIMIZE = 1 << 3,
META_MENU_OP_UNSHADE = 1 << 4,
META_MENU_OP_SHADE = 1 << 5,
META_MENU_OP_UNSTICK = 1 << 6,
META_MENU_OP_STICK = 1 << 7,
META_MENU_OP_WORKSPACES = 1 << 8
} MetaMenuOp;
struct _MenuItem
{
MetaMenuOp op;
@ -50,8 +37,7 @@ struct _MenuItem
struct _MenuData
{
MetaFrames *frames;
MetaUIFrame *frame;
MetaWindowMenu *menu;
MetaMenuOp op;
};
@ -92,70 +78,64 @@ popup_position_func (GtkMenu *menu,
}
static void
menu_closed (GtkMenu *menu,
menu_closed (GtkMenu *widget,
gpointer data)
{
MetaFrames *frames;
MetaWindowMenu *menu;
frames = META_FRAMES (data);
menu = data;
meta_frames_notify_menu_hide (frames);
meta_frames_notify_menu_hide (menu->frames);
(* menu->func) (menu, gdk_display,
menu->client_xwindow,
0, 0,
menu->data);
gtk_widget_destroy (frames->menu);
frames->menu = NULL;
/* menu may now be freed */
}
void
meta_window_menu_show (MetaFrames *frames,
MetaUIFrame *frame,
int root_x,
int root_y,
int button,
guint32 timestamp)
static void
activate_cb (GtkWidget *menuitem, gpointer data)
{
MenuData *md;
g_return_if_fail (GTK_IS_WIDGET (menuitem));
md = data;
meta_frames_notify_menu_hide (md->menu->frames);
(* md->menu->func) (md->menu, gdk_display,
md->menu->client_xwindow,
md->op,
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
"workspace")),
md->menu->data);
/* menu may now be freed */
}
MetaWindowMenu*
meta_window_menu_new (MetaFrames *frames,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
int active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
int i;
GdkPoint *pt;
int n_workspaces;
int current_workspace;
MetaMenuOp ops;
MetaMenuOp insensitive;
MetaFrameFlags flags;
MetaWindowMenu *menu;
flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
menu = g_new (MetaWindowMenu, 1);
menu->frames = frames;
menu->client_xwindow = client_xwindow;
menu->func = func;
menu->data = data;
menu->ops = ops;
menu->insensitive = insensitive;
ops = 0;
insensitive = 0;
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
{
if (flags & META_FRAME_MAXIMIZED)
ops |= META_MENU_OP_UNMAXIMIZE;
else
ops |= META_MENU_OP_MAXIMIZE;
}
if (flags & META_FRAME_SHADED)
ops |= META_MENU_OP_UNSHADE;
else
ops |= META_MENU_OP_SHADE;
if (flags & META_FRAME_STUCK)
ops |= META_MENU_OP_UNSTICK;
else
ops |= META_MENU_OP_STICK;
ops |= (META_MENU_OP_DELETE | META_MENU_OP_WORKSPACES | META_MENU_OP_MINIMIZE);
if (!(flags & META_FRAME_ALLOWS_MINIMIZE))
insensitive |= META_MENU_OP_MINIMIZE;
if (!(flags & META_FRAME_ALLOWS_DELETE))
insensitive |= META_MENU_OP_DELETE;
if (frames->menu)
gtk_widget_destroy (frames->menu);
frames->menu = gtk_menu_new ();
menu->menu = gtk_menu_new ();
i = 0;
while (i < G_N_ELEMENTS (menuitems))
@ -234,8 +214,7 @@ meta_window_menu_show (MetaFrames *frames,
md = g_new (MenuData, 1);
md->frames = frames;
md->frame = frame;
md->menu = menu;
md->op = menuitems[i].op;
gtk_signal_connect_full (GTK_OBJECT (mi),
@ -246,7 +225,7 @@ meta_window_menu_show (MetaFrames *frames,
g_free, FALSE, FALSE);
}
gtk_menu_shell_append (GTK_MENU_SHELL (frames->menu),
gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu),
mi);
gtk_widget_show (mi);
@ -256,12 +235,8 @@ meta_window_menu_show (MetaFrames *frames,
if (ops & META_MENU_OP_WORKSPACES)
{
n_workspaces = meta_core_get_num_workspaces (DefaultScreenOfDisplay (gdk_display));
current_workspace = meta_core_get_frame_workspace (gdk_display,
frame->xwindow);
meta_warning ("Creating %d-workspace menu current %d\n",
n_workspaces, current_workspace);
n_workspaces, active_workspace);
if (n_workspaces > 0)
{
@ -273,7 +248,7 @@ meta_window_menu_show (MetaFrames *frames,
char *label;
MenuData *md;
if (flags & META_FRAME_STUCK)
if (ops & META_MENU_OP_UNSTICK)
label = g_strdup_printf (_("Only on workspace _%d\n"),
i + 1);
else
@ -284,15 +259,14 @@ meta_window_menu_show (MetaFrames *frames,
g_free (label);
if (!(flags & META_FRAME_STUCK) &&
(current_workspace == i ||
if (!(ops & META_MENU_OP_UNSTICK) &&
(active_workspace == i ||
insensitive & META_MENU_OP_WORKSPACES))
gtk_widget_set_sensitive (mi, FALSE);
md = g_new (MenuData, 1);
md->frames = frames;
md->frame = frame;
md->menu = menu;
md->op = META_MENU_OP_WORKSPACES;
g_object_set_data (G_OBJECT (mi),
@ -306,7 +280,7 @@ meta_window_menu_show (MetaFrames *frames,
md,
g_free, FALSE, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (frames->menu),
gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu),
mi);
gtk_widget_show (mi);
@ -318,14 +292,26 @@ meta_window_menu_show (MetaFrames *frames,
else
meta_verbose ("not creating workspace menu\n");
gtk_signal_connect (GTK_OBJECT (frames->menu),
gtk_signal_connect (GTK_OBJECT (menu->menu),
"selection_done",
GTK_SIGNAL_FUNC (menu_closed),
frames);
menu);
return menu;
}
void
meta_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
GdkPoint *pt;
pt = g_new (GdkPoint, 1);
g_object_set_data_full (G_OBJECT (frames->menu),
g_object_set_data_full (G_OBJECT (menu->menu),
"destroy-point",
pt,
g_free);
@ -333,82 +319,19 @@ meta_window_menu_show (MetaFrames *frames,
pt->x = root_x;
pt->y = root_y;
gtk_menu_popup (GTK_MENU (frames->menu),
gtk_menu_popup (GTK_MENU (menu->menu),
NULL, NULL,
popup_position_func, pt,
button,
timestamp);
if (!GTK_MENU_SHELL (frames->menu)->have_xgrab)
if (!GTK_MENU_SHELL (menu->menu)->have_xgrab)
meta_warning ("GtkMenu failed to grab the pointer\n");
}
static void
activate_cb (GtkWidget *menuitem, gpointer data)
void
meta_window_menu_free (MetaWindowMenu *menu)
{
MenuData *md;
g_return_if_fail (GTK_IS_WIDGET (menuitem));
md = data;
switch (md->op)
{
case META_MENU_OP_DELETE:
meta_core_delete (gdk_display,
md->frame->xwindow,
gtk_get_current_event_time ());
break;
case META_MENU_OP_MINIMIZE:
meta_core_minimize (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_UNMAXIMIZE:
meta_core_unmaximize (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_MAXIMIZE:
meta_core_maximize (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_UNSHADE:
meta_core_unshade (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_SHADE:
meta_core_shade (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_WORKSPACES:
{
int workspace;
workspace = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
"workspace"));
meta_core_change_workspace (gdk_display, md->frame->xwindow,
workspace);
}
break;
case META_MENU_OP_STICK:
meta_core_stick (gdk_display,
md->frame->xwindow);
break;
case META_MENU_OP_UNSTICK:
meta_core_unstick (gdk_display,
md->frame->xwindow);
break;
default:
meta_warning (G_STRLOC": Unknown window op\n");
break;
}
gtk_widget_destroy (menu->menu);
g_free (menu);
}

View File

@ -25,14 +25,31 @@
#include <gtk/gtk.h>
#include "frames.h"
void meta_window_menu_show (MetaFrames *frames,
MetaUIFrame *frame,
struct _MetaWindowMenu
{
MetaFrames *frames;
Window client_xwindow;
GtkWidget *menu;
MetaWindowMenuFunc func;
gpointer data;
MetaMenuOp ops;
MetaMenuOp insensitive;
};
MetaWindowMenu* meta_window_menu_new (MetaFrames *frames,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
int active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data);
void meta_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_window_menu_free (MetaWindowMenu *menu);
#endif

View File

@ -50,6 +50,13 @@ set_wm_check_hint (MetaScreen *screen)
screen->display->atom_net_supporting_wm_check,
XA_WINDOW,
32, PropModeReplace, (guchar*) data, 1);
/* Legacy GNOME hint */
XChangeProperty (screen->display->xdisplay, screen->xroot,
screen->display->atom_win_supporting_wm_check,
XA_WINDOW,
32, PropModeReplace, (guchar*) data, 1);
return Success;
}
@ -57,6 +64,7 @@ static int
set_supported_hint (MetaScreen *screen)
{
#define N_SUPPORTED 21
#define N_WIN_SUPPORTED 1
Atom atoms[N_SUPPORTED];
atoms[0] = screen->display->atom_net_wm_name;
@ -86,6 +94,14 @@ set_supported_hint (MetaScreen *screen)
XA_ATOM,
32, PropModeReplace, (guchar*) atoms, N_SUPPORTED);
/* Set legacy GNOME hints */
atoms[0] = screen->display->atom_win_layer;
XChangeProperty (screen->display->xdisplay, screen->xroot,
screen->display->atom_win_protocols,
XA_ATOM,
32, PropModeReplace, (guchar*) atoms, N_WIN_SUPPORTED);
return Success;
#undef N_SUPPORTED
}

View File

@ -41,6 +41,8 @@ struct _MetaSessionInfo
MetaSessionInfo* meta_window_lookup_session_info (MetaWindow *window);
void meta_session_init (const char *previous_id);
#endif

View File

@ -22,6 +22,7 @@
#include "ui.h"
#include "frames.h"
#include "util.h"
#include "menu.h"
struct _MetaUI
{
@ -197,4 +198,37 @@ meta_ui_set_frame_title (MetaUI *ui,
meta_frames_set_title (ui->frames, xwindow, title);
}
MetaWindowMenu*
meta_ui_window_menu_new (MetaUI *ui,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
int active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
return meta_window_menu_new (ui->frames,
ops, insensitive,
client_xwindow,
active_workspace,
n_workspaces,
func, data);
}
void
meta_ui_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
meta_window_menu_popup (menu, root_x, root_y, button, timestamp);
}
void
meta_ui_window_menu_free (MetaWindowMenu *menu)
{
meta_window_menu_free (menu);
}

View File

@ -71,4 +71,21 @@ void meta_ui_set_frame_title (MetaUI *ui,
Window xwindow,
const char *title);
MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
int active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data);
void meta_ui_window_menu_popup (MetaWindowMenu *menu,
int root_x,
int root_y,
int button,
guint32 timestamp);
void meta_ui_window_menu_free (MetaWindowMenu *menu);
#endif

View File

@ -25,6 +25,8 @@
#include "errors.h"
#include "workspace.h"
#include "stack.h"
#include "keybindings.h"
#include "ui.h"
#include <X11/Xatom.h>
@ -210,6 +212,8 @@ meta_window_new (MetaDisplay *display, Window xwindow,
window->placed = window->mapped;
window->unmanaging = FALSE;
window->calc_showing_queued = FALSE;
window->keys_grabbed = FALSE;
window->grab_on_frame = FALSE;
window->unmaps_pending = 0;
@ -266,9 +270,12 @@ meta_window_new (MetaDisplay *display, Window xwindow,
set_wm_state (window, window->iconic ? IconicState : NormalState);
set_net_wm_state (window);
/* keys grab on client window if no frame */
if (window->decorated)
meta_window_ensure_frame (window);
meta_window_grab_keys (window);
space =
meta_display_get_workspace_by_screen_index (window->display,
window->screen,
@ -322,6 +329,9 @@ meta_window_free (MetaWindow *window)
window->unmanaging = TRUE;
if (window->display->focus_window == window)
window->display->focus_window = NULL;
meta_window_unqueue_calc_showing (window);
tmp = window->workspaces;
@ -345,10 +355,13 @@ meta_window_free (MetaWindow *window)
set_wm_state (window, WithdrawnState);
meta_display_unregister_x_window (window->display, window->xwindow);
if (window->frame)
meta_window_destroy_frame (window);
meta_window_ungrab_keys (window);
meta_display_unregister_x_window (window->display, window->xwindow);
/* Put back anything we messed up */
meta_error_trap_push (window->display);
if (window->border_width != 0)
@ -698,9 +711,13 @@ meta_window_unmaximize (MetaWindow *window)
void
meta_window_shade (MetaWindow *window)
{
meta_verbose ("Shading %s\n", window->desc);
if (!window->shaded)
{
window->shaded = TRUE;
meta_window_focus (window, CurrentTime);
meta_window_queue_move_resize (window);
meta_window_queue_calc_showing (window);
@ -711,6 +728,7 @@ meta_window_shade (MetaWindow *window)
void
meta_window_unshade (MetaWindow *window)
{
meta_verbose ("Unshading %s\n", window->desc);
if (window->shaded)
{
window->shaded = FALSE;
@ -1153,6 +1171,22 @@ meta_window_focus (MetaWindow *window,
meta_verbose ("Setting input focus to window %s, input: %d take_focus: %d\n",
window->desc, window->input, window->take_focus);
if (window->shaded && window->frame)
{
/* This is so we can still use keyboard shortcuts
* and still draw the window as focused.
*/
if (window->frame)
{
meta_verbose ("Focusing frame of %s\n", window->desc);
XSetInputFocus (window->display->xdisplay,
window->frame->xwindow,
RevertToPointerRoot,
CurrentTime);
}
}
else
{
meta_error_trap_push (window->display);
if (window->input)
@ -1172,6 +1206,7 @@ meta_window_focus (MetaWindow *window,
meta_error_trap_pop (window->display);
}
}
void
meta_window_change_workspace (MetaWindow *window,
@ -1504,6 +1539,34 @@ meta_window_client_message (MetaWindow *window,
return FALSE;
}
gboolean
meta_window_notify_focus (MetaWindow *window,
XEvent *event)
{
/* note the event can be on either the window or the frame,
* we focus the frame for shaded windows
*/
if (event->type == FocusIn)
{
if (window != window->display->focus_window)
window->display->focus_window = window;
window->has_focus = TRUE;
if (window->frame)
meta_frame_queue_draw (window->frame);
}
else if (event->type == FocusOut)
{
if (window == window->display->focus_window)
window->display->focus_window = NULL;
window->has_focus = FALSE;
if (window->frame)
meta_frame_queue_draw (window->frame);
}
return FALSE;
}
static gboolean
process_property_notify (MetaWindow *window,
XPropertyEvent *event)
@ -2797,3 +2860,144 @@ constrain_position (MetaWindow *window,
*new_x = x;
*new_y = y;
}
static void
menu_callback (MetaWindowMenu *menu,
Display *xdisplay,
Window client_xwindow,
MetaMenuOp op,
int workspace_index,
gpointer data)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, client_xwindow);
if (window != NULL) /* window can be NULL */
{
meta_verbose ("Menu op %d on %s\n", op, window->desc);
/* op can be 0 for none */
switch (op)
{
case META_MENU_OP_DELETE:
meta_window_delete (window, CurrentTime);
break;
case META_MENU_OP_MINIMIZE:
meta_window_minimize (window);
break;
case META_MENU_OP_UNMAXIMIZE:
meta_window_unmaximize (window);
break;
case META_MENU_OP_MAXIMIZE:
meta_window_maximize (window);
break;
case META_MENU_OP_UNSHADE:
meta_window_unshade (window);
break;
case META_MENU_OP_SHADE:
meta_window_shade (window);
break;
case META_MENU_OP_WORKSPACES:
{
MetaWorkspace *workspace;
workspace =
meta_display_get_workspace_by_screen_index (window->display,
window->screen,
workspace_index);
if (workspace)
meta_window_change_workspace (window,
workspace);
else
meta_warning ("Workspace %d doesn't exist\n", workspace_index);
}
break;
case META_MENU_OP_STICK:
meta_window_stick (window);
break;
case META_MENU_OP_UNSTICK:
meta_window_unstick (window);
break;
case 0:
/* nothing */
break;
default:
meta_warning (G_STRLOC": Unknown window op\n");
break;
}
}
else
{
meta_verbose ("Menu callback on nonexistent window\n");
}
meta_ui_window_menu_free (menu);
}
void
meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
Time timestamp)
{
MetaMenuOp ops;
MetaMenuOp insensitive;
MetaWindowMenu *menu;
ops = 0;
insensitive = 0;
ops |= (META_MENU_OP_DELETE | META_MENU_OP_WORKSPACES | META_MENU_OP_MINIMIZE);
if (window->maximized)
ops |= META_MENU_OP_UNMAXIMIZE;
else
ops |= META_MENU_OP_MAXIMIZE;
if (!window->has_maximize_func)
insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE;
if (window->shaded)
ops |= META_MENU_OP_UNSHADE;
else
ops |= META_MENU_OP_SHADE;
if (window->on_all_workspaces)
ops |= META_MENU_OP_UNSTICK;
else
ops |= META_MENU_OP_STICK;
if (!window->has_minimize_func)
insensitive |= META_MENU_OP_MINIMIZE;
if (!window->has_close_func)
insensitive |= META_MENU_OP_DELETE;
menu =
meta_ui_window_menu_new (window->screen->ui,
window->xwindow,
ops,
insensitive,
meta_window_get_net_wm_desktop (window),
meta_screen_get_n_workspaces (window->screen),
menu_callback,
NULL);
meta_verbose ("Popping up window menu for %s\n", window->desc);
meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp);
}

View File

@ -140,6 +140,10 @@ struct _MetaWindow
/* Are we in the calc_showing queue? */
guint calc_showing_queued : 1;
/* Used by keybindings.c */
guint keys_grabbed : 1;
guint grab_on_frame : 1;
/* Number of UnmapNotify that are caused by us, if
* we get UnmapNotify with none pending then the client
* is withdrawing the window.
@ -227,8 +231,17 @@ gboolean meta_window_property_notify (MetaWindow *window,
XEvent *event);
gboolean meta_window_client_message (MetaWindow *window,
XEvent *event);
gboolean meta_window_notify_focus (MetaWindow *window,
XEvent *event);
int meta_window_set_current_workspace_hint (MetaWindow *window);
unsigned long meta_window_get_net_wm_desktop (MetaWindow *window);
void meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
Time timestamp);
#endif