Commit bf64e719 authored by rhp's avatar rhp

...

parent 7ecf21af
......@@ -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
......@@ -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);
}
......@@ -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
......@@ -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 */
......
......@@ -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
......
......@@ -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
......@@ -117,7 +121,7 @@ meta_window_destroy_frame (MetaWindow *window)
return;
frame = window->frame;
meta_ui_remove_frame (window->screen->ui, frame->xwindow);
/* Unparent the client window; it may be destroyed,
......@@ -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;
......
......@@ -300,9 +300,6 @@ meta_frames_destroy (GtkObject *object)
MetaFrames *frames;
frames = META_FRAMES (object);
if (frames->menu)
gtk_widget_destroy (frames->menu);
winlist = NULL;
g_hash_table_foreach (frames->frames,
......@@ -856,13 +853,7 @@ meta_frames_end_grab (MetaFrames *frames,
guint32 timestamp)
{
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,11 +1021,12 @@ meta_frames_button_press_event (GtkWidget *widget,
if (status == META_FRAME_STATUS_CLICKING_MENU)
{
meta_window_menu_show (frames, frame,
event->x_root,
event->y_root,
event->button,
event->time);
meta_core_show_window_menu (gdk_display,
frame->xwindow,
event->x_root,
event->y_root,
event->button,
event->time);
}
}
else if (control == META_FRAME_CONTROL_RESIZE_SE &&
......
......@@ -89,8 +89,6 @@ struct _MetaFrames
int text_height;
GHashTable *frames;
GtkWidget *menu;
/* The below is all for grabs */
MetaFrameStatus grab_status;
......@@ -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
......@@ -22,6 +22,8 @@
#include "keybindings.h"
#include "workspace.h"
#include "errors.h"
#include "ui.h"
#include "frame.h"
#include <X11/keysym.h>
......@@ -30,12 +32,18 @@
*/
typedef void (* MetaKeyHandler) (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data);
static void handle_activate_workspace (MetaDisplay *display,
XEvent *event,
gpointer data);
MetaWindow *window,
XEvent *event,
gpointer data);
static void handle_activate_menu (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
gpointer data);
typedef struct _MetaKeyBinding MetaKeyBinding;
......@@ -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,41 +70,57 @@ 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);
++i;
}
}
}
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,18 +138,22 @@ meta_screen_grab_keys (MetaScreen *screen)
}
}
void
meta_screen_ungrab_keys (MetaScreen *screen)
static void
ungrab_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)
{
XUngrabKey (screen->display->xdisplay, bindings[i].keycode,
bindings[i].mask, screen->xroot);
meta_error_trap_push (display);
XUngrabKey (display->xdisplay, bindings[i].keycode,
bindings[i].mask, xwindow);
meta_error_trap_pop (display);
}
++i;
......@@ -135,8 +161,59 @@ meta_screen_ungrab_keys (MetaScreen *screen)
}
void
meta_display_process_key_press (MetaDisplay *display,
XEvent *event)
meta_screen_grab_keys (MetaScreen *screen)
{
grab_keys (screen_bindings, screen->display, screen->xroot);
}
void
meta_screen_ungrab_keys (MetaScreen *screen)
{
ungrab_keys (screen_bindings, screen->display, screen->xroot);
}
void
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;
int i;
......@@ -144,22 +221,32 @@ 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;
}
++i;
}
}
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);
}
}
......@@ -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
......
......@@ -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;
frames = META_FRAMES (data);
meta_frames_notify_menu_hide (frames);
MetaWindowMenu *menu;
menu = data;
gtk_widget_destroy (frames->menu);
frames->menu = NULL;
meta_frames_notify_menu_hide (menu->frames);
(* menu->func) (menu, gdk_display,
menu->client_xwindow,
0, 0,
menu->data);
/* 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)
{
int i;
GdkPoint *pt;
int n_workspaces;
int current_workspace;
MetaMenuOp ops;
MetaMenuOp insensitive;
MetaFrameFlags flags;
flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
MenuData *md;
ops = 0;
insensitive = 0;
g_return_if_fail (GTK_IS_WIDGET (menuitem));
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
{
if (flags & META_FRAME_MAXIMIZED)
ops |= META_MENU_OP_UNMAXIMIZE;
else
ops |= META_MENU_OP_MAXIMIZE;
}
md = data;
if (flags & META_FRAME_SHADED)
ops |= META_MENU_OP_UNSHADE;
else
ops |= META_MENU_OP_SHADE;
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);
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);
/* menu may now be freed */
}
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);
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;
MetaWindowMenu *menu;
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;
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,