Commit b6e4c8bc authored by rhp's avatar rhp
Browse files

...

parent 46edcc48
......@@ -31,8 +31,10 @@ METACITY FEATURES
letter in the menu item works.
Choose Move from menu, and arrow keys to move the window.
While moving, hold down Control to move slower, and
Shift to snap to edges.
Choose Resize from menu, and nothing happens yet, but
eventually I might implement something.
......@@ -85,11 +87,17 @@ METACITY FEATURES
look in frames.c:meta_frames_class_init() for all the style
properties that you can configure.
Metacity-specific styles can also be included in any GTK+
theme.
- Metacity implements much of the new window manager spec from
freedesktop.org, and much of the ICCCM. But then there are
parts of each that it doesn't implement, just because I haven't
yet.
- Uses Pango to render text, so has cool i18n capabilities.
Supports UTF-8 window titles and such.
METACITY BUGS, NON-FEATURES, AND CAVEATS
===
......@@ -154,6 +162,17 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS
Metacity needs to keep this area up-to-date using the hints the
panel sets.
- Should really support click-to-focus as an option.
- Windows has a neat way of implementing Alt-Tab for
window cycling that I would like to copy. (The little
popup window thing.)
- Should Metacity support flipping in right-to-left locales?
I don't know what window managers look like in a right-to-left
locale. I assume the window titles should be right-justified;
should the window controls also be flipped?
COMPILING METACITY
===
......@@ -161,22 +180,32 @@ You need GTK+ 1.3.x (to become 2.0). See configure.in for the exact
version you need. Metacity is a fairly trivial 6000-line C program, so
once you get GTK+ built it should be no problem to build Metacity.
REPORTING BUGS
REPORTING BUGS AND SUBMITTING PATCHES
===
Report new bugs to hp@redhat.com for now. Will switch to Bugzilla
sometime probably.
Feel free to send patches too; Metacity is really small and simple, so
if you find a bug or want to add a feature it should be pretty easy.
FAQ
===
Q: Will you add my feature?
A: Probably not, unless it makes sense to turn on by unconditionally,
A: If it makes sense to turn on unconditionally,
or is genuinely a harmless preference that I would not
be embarrassed to put in a user-friendly configuration dialog.
be embarrassed to put in a simple, uncluttered, user-friendly
configuration dialog.
If the only rationale for your feature is that other window
managers have it, or that you are personally used to it, or something
like that, then I will not be impressed. Metacity is firmly in the
"choose good defaults" camp rather than the "offer 6 equally broken
ways to do it, and let the user pick one" camp.
Metacity has a "no crackrock" policy, with some exceptions
This is part of a "no crackrock" policy, despite some exceptions
I'm mildly embarrassed about. For example, multiple workspaces
probably constitute crackrock, they confuse most users
and really are not that useful if you have a decent tasklist and
......@@ -185,7 +214,11 @@ A: Probably not, unless it makes sense to turn on by unconditionally,
keybindings are definitely on crack.
But don't think unlimited crack is OK just because I slipped up a
little. No slippery slope here.
little. No slippery slope here.
Don't let this discourage patches and fixes - I love those. ;-)
Just be prepared to hear the above objections if your patch
adds some crack-ridden configuration option.
Q: How do I add a configuration option?
......@@ -196,10 +229,12 @@ Q: Will Metacity be part of GNOME?
A: If Metacity is ever better than the other options, and the GNOME
Project so chooses. But Metacity may continue to suck forever
because I might get tired of it; or Metacity's conservative
nature might not make sense for the snazzy world of
GNOME. Who knows. I'm not worrying about this, and you shouldn't
either.
because I might get tired of working on it; or Metacity's feature
set might not make sense for GNOME. Who knows. I'm not worrying
about this, and you shouldn't either.
For now Metacity is my toy hobby project that I work on when I feel
like it.
Q: Why can't I move XMMS?
......
......@@ -70,6 +70,7 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
typedef enum
{
META_GRAB_OP_NONE,
/* Mouse ops */
META_GRAB_OP_MOVING,
META_GRAB_OP_RESIZING_SE,
META_GRAB_OP_RESIZING_S,
......@@ -79,14 +80,35 @@ typedef enum
META_GRAB_OP_RESIZING_NW,
META_GRAB_OP_RESIZING_W,
META_GRAB_OP_RESIZING_E,
/* Keyboard ops */
META_GRAB_OP_KEYBOARD_MOVING,
META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
META_GRAB_OP_KEYBOARD_RESIZING_S,
META_GRAB_OP_KEYBOARD_RESIZING_N,
META_GRAB_OP_KEYBOARD_RESIZING_W,
META_GRAB_OP_KEYBOARD_RESIZING_E
META_GRAB_OP_KEYBOARD_RESIZING_E,
/* Frame button ops */
META_GRAB_OP_CLICKING_MINIMIZE,
META_GRAB_OP_CLICKING_MAXIMIZE,
META_GRAB_OP_CLICKING_DELETE,
META_GRAB_OP_CLICKING_MENU
} MetaGrabOp;
typedef enum
{
META_CURSOR_DEFAULT,
META_CURSOR_NORTH_RESIZE,
META_CURSOR_SOUTH_RESIZE,
META_CURSOR_WEST_RESIZE,
META_CURSOR_EAST_RESIZE,
META_CURSOR_SE_RESIZE,
META_CURSOR_SW_RESIZE,
META_CURSOR_NE_RESIZE,
META_CURSOR_NW_RESIZE
} MetaCursor;
#endif
......
......@@ -393,3 +393,104 @@ meta_core_show_window_menu (Display *xdisplay,
meta_window_show_menu (window, root_x, root_y, button, timestamp);
}
gboolean
meta_core_begin_grab_op (Display *xdisplay,
Window frame_xwindow,
MetaGrabOp op,
gboolean pointer_already_grabbed,
int button,
gulong modmask,
Time timestamp,
int root_x,
int root_y)
{
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);
return meta_display_begin_grab_op (display, window,
op, pointer_already_grabbed,
button, modmask,
timestamp, root_x, root_y);
}
void
meta_core_end_grab_op (Display *xdisplay,
Time timestamp)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
meta_display_end_grab_op (display, timestamp);
}
MetaGrabOp
meta_core_get_grab_op (Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
return display->grab_op;
}
Window
meta_core_get_grab_frame (Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display->grab_op != META_GRAB_OP_NONE &&
display->grab_window->frame)
return display->grab_window->frame->xwindow;
else
return None;
}
int
meta_core_get_grab_button (Display *xdisplay)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
if (display->grab_op == META_GRAB_OP_NONE)
return -1;
return display->grab_button;
}
void
meta_core_grab_buttons (Display *xdisplay,
Window frame_xwindow)
{
MetaDisplay *display;
display = meta_display_for_x_display (xdisplay);
meta_display_grab_window_buttons (display, frame_xwindow);
}
void
meta_core_set_screen_cursor (Display *xdisplay,
Window frame_on_screen,
MetaCursor cursor)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, frame_on_screen);
if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_on_screen);
meta_screen_set_cursor (window->screen, cursor);
}
......@@ -94,7 +94,6 @@ int meta_core_get_active_workspace (Screen *xscreen);
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,
......@@ -102,6 +101,31 @@ void meta_core_show_window_menu (Display *xdisplay,
int button,
Time timestamp);
gboolean meta_core_begin_grab_op (Display *xdisplay,
Window frame_xwindow,
MetaGrabOp op,
gboolean pointer_already_grabbed,
int button,
gulong modmask,
Time timestamp,
int root_x,
int root_y);
void meta_core_end_grab_op (Display *xdisplay,
Time timestamp);
MetaGrabOp meta_core_get_grab_op (Display *xdisplay);
Window meta_core_get_grab_frame (Display *xdisplay);
int meta_core_get_grab_button (Display *xdisplay);
void meta_core_grab_buttons (Display *xdisplay,
Window frame_xwindow);
void meta_core_set_screen_cursor (Display *xdisplay,
Window frame_on_screen,
MetaCursor cursor);
#endif
......@@ -29,6 +29,7 @@
#include "keybindings.h"
#include "workspace.h"
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <string.h>
#define USE_GDK_DISPLAY
......@@ -554,6 +555,47 @@ event_queue_callback (XEvent *event,
event_callback (event, data);
}
static gboolean
grab_op_is_mouse (MetaGrabOp op)
{
switch (op)
{
case META_GRAB_OP_MOVING:
case META_GRAB_OP_RESIZING_SE:
case META_GRAB_OP_RESIZING_S:
case META_GRAB_OP_RESIZING_SW:
case META_GRAB_OP_RESIZING_N:
case META_GRAB_OP_RESIZING_NE:
case META_GRAB_OP_RESIZING_NW:
case META_GRAB_OP_RESIZING_W:
case META_GRAB_OP_RESIZING_E:
return TRUE;
break;
default:
return FALSE;
}
}
static gboolean
grab_op_is_keyboard (MetaGrabOp op)
{
switch (op)
{
case META_GRAB_OP_KEYBOARD_MOVING:
case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
case META_GRAB_OP_KEYBOARD_RESIZING_S:
case META_GRAB_OP_KEYBOARD_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_E:
return TRUE;
break;
default:
return FALSE;
}
}
static gboolean
event_callback (XEvent *event,
gpointer data)
......@@ -609,18 +651,48 @@ event_callback (XEvent *event,
meta_display_process_key_event (display, window, event);
break;
case ButtonPress:
if (display->grab_op != META_GRAB_OP_NONE)
if ((grab_op_is_mouse (display->grab_op) &&
display->grab_button != event->xbutton.button &&
display->grab_window == window) ||
grab_op_is_keyboard (display->grab_op))
{
meta_verbose ("Ending grab op %d on window %s due to button press\n",
display->grab_op,
display->grab_window->desc);
meta_display_end_grab_op (display,
event->xbutton.time);
}
else if (window)
{
if (event->xbutton.button == 1)
{
meta_window_raise (window);
meta_window_focus (window, event->xbutton.time);
}
else if (event->xbutton.button == 2)
{
/* FIXME begin move */
}
else if (event->xbutton.button == 3)
{
meta_window_show_menu (window,
event->xbutton.x_root,
event->xbutton.y_root,
event->xbutton.button,
event->xbutton.time);
}
}
break;
case ButtonRelease:
if (grab_op_is_mouse (display->grab_op) &&
display->grab_window == window)
meta_window_handle_mouse_grab_op_event (window, event);
break;
case MotionNotify:
if (grab_op_is_mouse (display->grab_op) &&
display->grab_window == window)
meta_window_handle_mouse_grab_op_event (window, event);
break;
case EnterNotify:
/* do this even if window->has_focus to avoid races */
......@@ -649,6 +721,10 @@ event_callback (XEvent *event,
case DestroyNotify:
if (window)
{
if (display->grab_op != META_GRAB_OP_NONE &&
display->grab_window == window)
meta_display_end_grab_op (display, CurrentTime);
if (frame_was_receiver)
{
meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n",
......@@ -664,6 +740,14 @@ event_callback (XEvent *event,
}
break;
case UnmapNotify:
if (display->grab_op != META_GRAB_OP_NONE &&
display->grab_window == window)
meta_display_end_grab_op (display, CurrentTime);
/* Unfocus on UnmapNotify */
if (window)
meta_window_notify_focus (window, event);
if (!frame_was_receiver && window)
{
if (window->unmaps_pending == 0)
......@@ -932,7 +1016,6 @@ static void
meta_spew_event (MetaDisplay *display,
XEvent *event)
{
const char *name = NULL;
char *extra = NULL;
char *winname;
......@@ -1208,6 +1291,94 @@ meta_display_get_workspace_by_screen_index (MetaDisplay *display,
return NULL;
}
Cursor
meta_display_create_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
Cursor xcursor;
guint glyph;
switch (cursor)
{
case META_CURSOR_DEFAULT:
glyph = XC_left_ptr;
break;
case META_CURSOR_NORTH_RESIZE:
glyph = XC_top_side;
break;
case META_CURSOR_SOUTH_RESIZE:
glyph = XC_bottom_side;
break;
case META_CURSOR_WEST_RESIZE:
glyph = XC_left_side;
break;
case META_CURSOR_EAST_RESIZE:
glyph = XC_right_side;
break;
case META_CURSOR_SE_RESIZE:
glyph = XC_bottom_right_corner;
break;
case META_CURSOR_SW_RESIZE:
glyph = XC_bottom_left_corner;
break;
case META_CURSOR_NE_RESIZE:
glyph = XC_top_left_corner;
break;
case META_CURSOR_NW_RESIZE:
glyph = XC_top_right_corner;
break;
default:
g_assert_not_reached ();
glyph = 0; /* silence compiler */
break;
}
xcursor = XCreateFontCursor (display->xdisplay, glyph);
return xcursor;
}
static Cursor
xcursor_for_op (MetaDisplay *display,
MetaGrabOp op)
{
MetaCursor cursor = META_CURSOR_DEFAULT;
switch (display->grab_op)
{
case META_GRAB_OP_RESIZING_SE:
cursor = META_CURSOR_SE_RESIZE;
break;
case META_GRAB_OP_RESIZING_S:
cursor = META_CURSOR_SOUTH_RESIZE;
break;
case META_GRAB_OP_RESIZING_SW:
cursor = META_CURSOR_SW_RESIZE;
break;
case META_GRAB_OP_RESIZING_N:
cursor = META_CURSOR_NORTH_RESIZE;
break;
case META_GRAB_OP_RESIZING_NE:
cursor = META_CURSOR_NE_RESIZE;
break;
case META_GRAB_OP_RESIZING_NW:
cursor = META_CURSOR_NW_RESIZE;
break;
case META_GRAB_OP_RESIZING_W:
cursor = META_CURSOR_WEST_RESIZE;
break;
case META_GRAB_OP_RESIZING_E:
cursor = META_CURSOR_EAST_RESIZE;
break;
default:
break;
}
return meta_display_create_x_cursor (display, cursor);
}
gboolean
meta_display_begin_grab_op (MetaDisplay *display,
MetaWindow *window,
......@@ -1215,13 +1386,13 @@ meta_display_begin_grab_op (MetaDisplay *display,
gboolean pointer_already_grabbed,
int button,
gulong modmask,
Cursor cursor,
Time timestamp,
int root_x,
int root_y)
{
Window grabwindow;
Cursor cursor;
meta_verbose ("Doing grab op %d on window %s button %d pointer already grabbed: %d\n",
op, window->desc, button, pointer_already_grabbed);
......@@ -1233,27 +1404,31 @@ meta_display_begin_grab_op (MetaDisplay *display,
op, window->desc, display->grab_op, display->grab_window->desc);
return FALSE;
}
if (pointer_already_grabbed)
{
display->grab_have_pointer = TRUE;
}
else
{
meta_error_trap_push (display);
if (XGrabPointer (display->xdisplay,
grabwindow,
False,
PointerMotionMask | PointerMotionHintMask |
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask,
GrabModeAsync, GrabModeAsync,
None,
cursor,
timestamp) == GrabSuccess)
display->grab_have_pointer = TRUE;
meta_error_trap_pop (display);
}
display->grab_have_pointer = TRUE;
/* We XGrabPointer even if we already have an autograb,
* just to set the cursor and event mask
*/
cursor = xcursor_for_op (display, op);
meta_error_trap_push (display);
if (XGrabPointer (display->xdisplay,
grabwindow,
False,
PointerMotionMask | PointerMotionHintMask |
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask,
GrabModeAsync, GrabModeAsync,
None,
cursor,
timestamp) == GrabSuccess)
display->grab_have_pointer = TRUE;
meta_error_trap_pop (display);
XFreeCursor (display->xdisplay, cursor);
if (!display->grab_have_pointer)
{
......@@ -1283,7 +1458,6 @@ meta_display_begin_grab_op (MetaDisplay *display,
/* non-keyboard grab ops */
break;
}
display->grab_op = op;
display->grab_window = window;
......@@ -1316,7 +1490,67 @@ meta_display_end_grab_op (MetaDisplay *display,
if (display->grab_have_keyboard)
meta_window_ungrab_all_keys (display->grab_window);
display->grab_window = NULL;
display->grab_op = META_GRAB_OP_NONE;
display->grab_op = META_GRAB_OP_NONE;
}
void
meta_display_grab_window_buttons (MetaDisplay *display,
Window xwindow)
{
/* Grab Alt + button1 and Alt + button2 for moving window,
* and Alt + button3 for popping up window menu.
*/
{
int i = 1;
while (i < 4)
{
int result;
meta_error_trap_push (display);
XGrabButton (display->xdisplay, i, Mod1Mask,
xwindow, False,
ButtonPressMask | ButtonReleaseMask |