diff -uN metacity-2.5.2-base/src/Makefile.am metacity-2.5.2-patch/src/Makefile.am --- metacity-2.5.2-base/src/Makefile.am 2003-04-21 19:34:45.000000000 -0400 +++ metacity-2.5.2-patch/src/Makefile.am 2003-08-30 14:58:33.000000000 -0400 @@ -31,6 +31,7 @@ eventqueue.h \ fixedtip.c \ fixedtip.h \ + flip.c \ frame.c \ frame.h \ frames.c \ diff -uN metacity-2.5.2-base/src/Makefile.in metacity-2.5.2-patch/src/Makefile.in --- metacity-2.5.2-base/src/Makefile.in 2003-05-20 12:32:21.000000000 -0400 +++ metacity-2.5.2-patch/src/Makefile.in 2003-08-30 14:57:52.000000000 -0400 @@ -122,7 +122,7 @@ EGGFILES = eggaccelerators.c eggaccelerators.h -metacity_SOURCES = async-getprop.c async-getprop.h bell.h bell.c common.h constraints.c constraints.h core.c core.h delete.c display.c display.h draw-workspace.c draw-workspace.h effects.c effects.h errors.c errors.h eventqueue.c eventqueue.h fixedtip.c fixedtip.h frame.c frame.h frames.c frames.h gradient.c gradient.h group.c group.h group-private.h group-props.c group-props.h iconcache.c iconcache.h inlinepixbufs.h keybindings.c keybindings.h main.c main.h menu.c menu.h metaaccellabel.c metaaccellabel.h metacity-Xatomtype.h place.c place.h prefs.c prefs.h resizepopup.c resizepopup.h screen.c screen.h session.c session.h stack.c stack.h tabpopup.c tabpopup.h theme.c theme.h theme-parser.c theme-parser.h themewidget.c themewidget.h ui.c ui.h util.c util.h window.c window.h window-props.c window-props.h workspace.c workspace.h xprops.c xprops.h $(EGGFILES) +metacity_SOURCES = async-getprop.c async-getprop.h bell.h bell.c common.h constraints.c constraints.h core.c core.h delete.c display.c display.h draw-workspace.c draw-workspace.h effects.c effects.h errors.c errors.h eventqueue.c eventqueue.h fixedtip.c fixedtip.h frame.c frame.h frames.c frames.h gradient.c gradient.h group.c group.h group-private.h group-props.c group-props.h iconcache.c iconcache.h inlinepixbufs.h keybindings.c keybindings.h main.c main.h menu.c menu.h metaaccellabel.c metaaccellabel.h metacity-Xatomtype.h place.c place.h prefs.c prefs.h resizepopup.c resizepopup.h screen.c screen.h session.c session.h stack.c stack.h tabpopup.c tabpopup.h theme.c theme.h theme-parser.c theme-parser.h themewidget.c themewidget.h ui.c ui.h util.c util.h window.c window.h window-props.c window-props.h workspace.c workspace.h xprops.c xprops.h flip.c $(EGGFILES) libmetacity_private_la_SOURCES = gradient.c gradient.h preview-widget.c preview-widget.h theme.c theme.h theme-parser.c theme-parser.h util.c util.h common.h @@ -207,7 +207,7 @@ metacity_OBJECTS = async-getprop.$(OBJEXT) bell.$(OBJEXT) \ constraints.$(OBJEXT) core.$(OBJEXT) delete.$(OBJEXT) display.$(OBJEXT) \ draw-workspace.$(OBJEXT) effects.$(OBJEXT) errors.$(OBJEXT) \ -eventqueue.$(OBJEXT) fixedtip.$(OBJEXT) frame.$(OBJEXT) \ +eventqueue.$(OBJEXT) fixedtip.$(OBJEXT) flip.$(OBJEXT) frame.$(OBJEXT) \ frames.$(OBJEXT) gradient.$(OBJEXT) group.$(OBJEXT) \ group-props.$(OBJEXT) iconcache.$(OBJEXT) keybindings.$(OBJEXT) \ main.$(OBJEXT) menu.$(OBJEXT) metaaccellabel.$(OBJEXT) place.$(OBJEXT) \ @@ -625,6 +625,7 @@ common.h eventqueue.o: eventqueue.c eventqueue.h fixedtip.o: fixedtip.c ../config.h fixedtip.h +flip.o: flip.c ../config.h frame.o: frame.c ../config.h frame.h window.h screen.h display.h \ eventqueue.h common.h ui.h tabpopup.h util.h stack.h \ iconcache.h bell.h errors.h keybindings.h diff -uN metacity-2.5.2-base/src/display.c metacity-2.5.2-patch/src/display.c --- metacity-2.5.2-base/src/display.c 2003-05-16 17:53:42.000000000 -0400 +++ metacity-2.5.2-patch/src/display.c 2003-08-30 14:56:35.000000000 -0400 @@ -96,6 +96,10 @@ static void prefs_changed_callback (MetaPreference pref, void *data); +int meta_flip_event( int xl, int yt ); +void meta_flip_init( MetaScreen * mscr ); + + static void set_utf8_string_hint (MetaDisplay *display, @@ -611,9 +615,9 @@ meta_error_trap_pop (display, FALSE); } - + meta_flip_init(display->screens->data); meta_display_ungrab (display); - + return TRUE; } @@ -1430,6 +1434,14 @@ meta_window_handle_mouse_grab_op_event (window, event); break; case EnterNotify: + { + XEnterWindowEvent *ewp = &(event->xcrossing); + if( meta_flip_event( ewp->x_root, ewp->y_root ) ) + { + break; + } + } + if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) meta_window_handle_mouse_grab_op_event (window, event); diff -uN metacity-2.5.2-base/src/flip.c metacity-2.5.2-patch/src/flip.c --- metacity-2.5.2-base/src/flip.c 1969-12-31 19:00:00.000000000 -0500 +++ metacity-2.5.2-patch/src/flip.c 2003-08-30 14:56:35.000000000 -0400 @@ -0,0 +1,529 @@ +/* Metacity Edge Flip Handling */ + +/* + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2002, 2003 Red Hat Inc. + * Some edge flip code derived from fvwm2 by John Rothe. + * Some ICCCM manager selection code derived from fvwm2, + * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team + * Copyright (C) 2003 Rob Adams + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include "display.h" +#include "util.h" +#include "main.h" +#include "screen.h" +#include "window.h" +#include "window-props.h" +#include "group-props.h" +#include "frame.h" +#include "errors.h" +#include "keybindings.h" +#include "prefs.h" +#include "resizepopup.h" +#include "workspace.h" +#include +#include +#ifdef HAVE_SOLARIS_XINERAMA +#include +#endif +#ifdef HAVE_XFREE_XINERAMA +#include +#endif +#ifdef HAVE_RANDR +#include +#endif +#ifdef HAVE_SHAPE +#include +#endif +#include + +#define USE_GDK_DISPLAY + + + +/* the root window is surrounded by four window slices, which are InputOnly. + * So you can see 'through' them, but they eat the input. An EnterEvent in + * one of these windows causes a Paging. The windows have the according cursor + * pointing in the pan direction or are hidden if there is no more panning + * in that direction. This is mostly intended to get a panning even atop + * of Motif applictions, which does not work yet. It seems Motif windows + * eat all mouse events. + * + * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94 +**/ + +#define XEVMASK_PANFW (ButtonPressMask | ButtonReleaseMask | \ + KeyReleaseMask | KeyPressMask | \ + EnterWindowMask | LeaveWindowMask | \ + VisibilityChangeMask) +/* Don't page if the pointer has moved for more than this many pixels between + * two samples */ +#define MAX_PAGING_MOVE_DISTANCE 10 /* pixels */ + +typedef struct { + Window win; // window ID + int isMapped; +} PanFrame; + +PanFrame PanFrameTop; +PanFrame PanFrameLeft; +PanFrame PanFrameRight; +PanFrame PanFrameBottom; +unsigned ScrollResistance = 100; +int MyDisplayHeight = 0; +int MyDisplayWidth = 0; +int edge_thickness = 2; +Time lastTimestamp = 0; +XEvent Event; /* the current event */ +MetaScreen *mscreen; +Display *dpy = NULL; /* which display are we talking to */ +MetaDisplay *mdpy = NULL; + +/** External hooks **/ +void meta_flip_init( MetaScreen * mscr ); +void meta_flip_update_frames ( void ); +int meta_flip_event( int xl, int yt ); +void meta_flip_raise_frames( void ); + + +/* Records the time of the last processed event. Used in XSetInputFocus */ +Bool StashEventTime ( XEvent * ev ); +void initPanFrames( void ); +Bool has_neighbor( MetaMotionDirection direction ); +Bool GetLocationFromEventOrQuery ( Display * dpy, Window w, XEvent * eventp, int *ret_x, int *ret_y ); +int discard_events ( long event_mask ); +int discard_window_events ( Window w, long event_mask ); +Window create_pan_frame( int x, int y, int width, int height, + unsigned int valuemask, XSetWindowAttributes *attributes ); + +void +meta_flip_init( MetaScreen * mscr ) +{ + mscreen = mscr; + mdpy = mscreen->display; + dpy = mdpy->xdisplay; + + meta_display_ungrab( mdpy ); + initPanFrames(); + meta_display_grab( mdpy ); + meta_flip_update_frames(); +} + + + +/*************************************************************************** + * meta_flip_update_frames hides PanFrames if they are on the very border of the + * VIRTUAL screen and EdgeWrap for that direction is off. + * (A special cursor for the EdgeWrap border could be nice) HEDU + ****************************************************************************/ +void +meta_flip_update_frames( void ) +{ + if( mscreen == NULL ) + return; + Bool do_unmap_l = !has_neighbor( META_MOTION_LEFT ); + Bool do_unmap_r = !has_neighbor( META_MOTION_RIGHT ); + Bool do_unmap_t = !has_neighbor( META_MOTION_UP ); + Bool do_unmap_b = !has_neighbor( META_MOTION_DOWN ); + + /* thickness of 0 means remove the pan frames */ + if( edge_thickness == 0 ) { + do_unmap_l = True; + do_unmap_r = True; + do_unmap_t = True; + do_unmap_b = True; + } + + /* left */ + if( do_unmap_l ) { + if( PanFrameLeft.isMapped ) { + XUnmapWindow ( dpy, PanFrameLeft.win ); + PanFrameLeft.isMapped = False; + } + } else { + if( !PanFrameLeft.isMapped ) { + XMapRaised ( dpy, PanFrameLeft.win ); + PanFrameLeft.isMapped = True; + } + } + /* right */ + if( do_unmap_r ) { + if( PanFrameRight.isMapped ) { + XUnmapWindow ( dpy, PanFrameRight.win ); + PanFrameRight.isMapped = False; + } + } else { + if( !PanFrameRight.isMapped ) { + XMapRaised ( dpy, PanFrameRight.win ); + PanFrameRight.isMapped = True; + } + } + /* top */ + if( do_unmap_t ) { + if( PanFrameTop.isMapped ) { + XUnmapWindow ( dpy, PanFrameTop.win ); + PanFrameTop.isMapped = False; + } + } else { + if( !PanFrameTop.isMapped ) { + XMapRaised ( dpy, PanFrameTop.win ); + PanFrameTop.isMapped = True; + } + } + /* bottom */ + if( do_unmap_b ) { + if( PanFrameBottom.isMapped ) { + XUnmapWindow ( dpy, PanFrameBottom.win ); + PanFrameBottom.isMapped = False; + } + } else { + if( !PanFrameBottom.isMapped ) { + XMapRaised ( dpy, PanFrameBottom.win ); + PanFrameBottom.isMapped = True; + } + } + return; +} + + +/**************************************************************************** + * + * Creates the windows for edge-scrolling + * + ****************************************************************************/ +void +initPanFrames( ) +{ + MyDisplayWidth = DisplayWidth ( dpy, mscreen->number ); + MyDisplayHeight = DisplayHeight ( dpy, mscreen->number ); + XSetWindowAttributes attributes; + unsigned long valuemask = ( CWEventMask | CWCursor ); + + int saved_thickness = edge_thickness; + if( edge_thickness == 0 ) + edge_thickness = 2; + + attributes.event_mask = XEVMASK_PANFW; + + /* I know these overlap, it's useful when at (0,0) and the top one is + * unmapped */ + attributes.cursor = meta_display_create_x_cursor( mdpy, META_CURSOR_NORTH_RESIZE ); + PanFrameTop.win = create_pan_frame( 0, 0, MyDisplayWidth, edge_thickness, valuemask, &attributes); + + attributes.cursor = meta_display_create_x_cursor( mdpy, META_CURSOR_WEST_RESIZE); + PanFrameLeft.win = create_pan_frame( 0, 0, edge_thickness, MyDisplayHeight, valuemask, &attributes); + + attributes.cursor = meta_display_create_x_cursor( mdpy, META_CURSOR_EAST_RESIZE ); + PanFrameRight.win = create_pan_frame( MyDisplayWidth - edge_thickness, 0, + edge_thickness, MyDisplayHeight, + valuemask, &attributes); + + attributes.cursor = meta_display_create_x_cursor( mdpy, META_CURSOR_SOUTH_RESIZE ); + PanFrameBottom.win = create_pan_frame( 0, MyDisplayHeight - edge_thickness, + MyDisplayWidth, edge_thickness, + valuemask, &attributes); + + PanFrameTop.isMapped = False; + PanFrameLeft.isMapped = False; + PanFrameRight.isMapped = False; + PanFrameBottom.isMapped = False; + + edge_thickness = saved_thickness; + +} +void +meta_flip_raise_frames( void ) +{ + if( PanFrameTop.isMapped ) + XRaiseWindow ( dpy, PanFrameTop.win ); + if( PanFrameLeft.isMapped ) + XRaiseWindow ( dpy, PanFrameLeft.win ); + if( PanFrameRight.isMapped ) + XRaiseWindow ( dpy, PanFrameRight.win ); + if( PanFrameBottom.isMapped ) + XRaiseWindow ( dpy, PanFrameBottom.win ); +} + +/** + * + * Check to see if the pointer is on the edge of the screen, and scroll/page + * if needed +**/ +int +meta_flip_event( int xl, int yt ) +{ + + static unsigned int add_time = 0; + int x, y; + XEvent e; + static Time my_timestamp = 0; + static Time my_last_timestamp = 0; + static Bool is_timestamp_valid = False; + static int last_x = 0; + static int last_y = 0; + static Bool is_last_position_valid = False; + + if( ScrollResistance >= 10000 ) { + is_timestamp_valid = False; + add_time = 0; + return 0; + } + if( !is_timestamp_valid ) { + is_timestamp_valid = True; + my_timestamp = lastTimestamp; + is_last_position_valid = False; + add_time = 0; + last_x = -1; + last_y = -1; + } else if( my_last_timestamp != lastTimestamp ) { + add_time = 0; + } + my_last_timestamp = lastTimestamp; + + do { + if( XPending ( dpy ) > 0 && + ( XCheckWindowEvent ( dpy, PanFrameTop.win, LeaveWindowMask, &Event ) || + XCheckWindowEvent ( dpy, PanFrameBottom.win, LeaveWindowMask, &Event ) || + XCheckWindowEvent ( dpy, PanFrameLeft.win, LeaveWindowMask, &Event ) || + XCheckWindowEvent ( dpy, PanFrameRight.win, LeaveWindowMask, &Event ) ) ) + { + StashEventTime ( &Event ); + is_timestamp_valid = False; + add_time = 0; + return 0; + } else if( XCheckMaskEvent ( dpy, ButtonPressMask | ButtonReleaseMask, &e ) ) { + XPutBackEvent ( dpy, &e ); + is_timestamp_valid = False; + add_time = 0; + return 0; + } + /* get pointer location */ + GetLocationFromEventOrQuery ( dpy, mscreen->xroot, &Event, &x, &y ); + /* check actual pointer location since PanFrames can get buried under + a window being moved or resized - mab */ + if( x >= edge_thickness && x < MyDisplayWidth - edge_thickness && + y >= edge_thickness && y < MyDisplayHeight - edge_thickness ) + { + is_timestamp_valid = False; + add_time = 0; + discard_window_events ( PanFrameTop.win, LeaveWindowMask ); + discard_window_events ( PanFrameBottom.win, LeaveWindowMask ); + discard_window_events ( PanFrameLeft.win, LeaveWindowMask ); + discard_window_events ( PanFrameRight.win, LeaveWindowMask ); + return 0; + } + last_x = x; + last_y = y; + is_last_position_valid = True; + usleep ( 10000 ); + add_time += 10; + } while( lastTimestamp - my_timestamp + add_time < ScrollResistance ); + + if( lastTimestamp - my_timestamp + add_time < ScrollResistance ) { + return 0; + } + + /* determine the flip direction and mouse destination */ + MetaMotionDirection direction; + if( x < edge_thickness ) { + direction = META_MOTION_LEFT; + xl = MyDisplayWidth - edge_thickness - 2; + } else if( x >= MyDisplayWidth - edge_thickness ) { + direction = META_MOTION_RIGHT; + xl = edge_thickness + 2; + } else if( y < edge_thickness ) { + direction = META_MOTION_UP; + yt = MyDisplayHeight - edge_thickness - 2; + } else if( y >= MyDisplayHeight - edge_thickness ) { + direction = META_MOTION_DOWN; + yt = edge_thickness + 2; + } else { + return 0; + } + + is_timestamp_valid = False; + add_time = 0; + MetaWorkspace *flipto = meta_workspace_get_neighbor( mscreen->active_workspace, + direction); + + if( flipto != NULL && flipto != mscreen->active_workspace ) { + Window junkW = 0; + int junkV = 0; + unsigned int junkMask = 0; + XWarpPointer ( dpy, None, mscreen->xroot, 0, 0, 0, 0, xl, yt ); + meta_workspace_activate( flipto ); + XQueryPointer ( dpy, mscreen->xroot, &junkW, &junkW, + &xl, &yt, &junkV, &junkV, &junkMask ); + return 1; + } else { + return 0; + } +} + + +/* + * This function determines the location of the mouse pointer from the event + * if possible, if not it queries the X server. Returns False if it had to + * query the server and the call failed. + */ +Bool +GetLocationFromEventOrQuery ( Display * dpy, Window w, XEvent * eventp, int *ret_x, int *ret_y ) +{ + Window JunkW; + int JunkC; + unsigned int JunkM; + + switch ( eventp->type ) { + case ButtonPress: + case ButtonRelease: + *ret_x = eventp->xbutton.x_root; + *ret_y = eventp->xbutton.y_root; + return True; + case KeyPress: + case KeyRelease: + *ret_x = eventp->xkey.x_root; + *ret_y = eventp->xkey.y_root; + return True; + case MotionNotify: + if( eventp->xmotion.same_screen == True ) { + *ret_x = eventp->xmotion.x_root; + *ret_y = eventp->xmotion.y_root; + } else { + /* pointer is on different screen */ + *ret_x = 0; + *ret_y = 0; + } + return True; + default: + return XQueryPointer ( dpy, w, &JunkW, &JunkW, ret_x, ret_y, &JunkC, &JunkC, &JunkM ); + } + +} + + +/* This function discards all queued up ButtonPress, ButtonRelease and + * ButtonMotion events. */ +int +discard_events ( long event_mask ) +{ + XEvent e; + int count; + + XSync ( dpy, 0 ); + for( count = 0; XCheckMaskEvent ( dpy, event_mask, &e ); count++ ) { + StashEventTime ( &e ); + } + + return count; +} + +/* This function discards all queued up ButtonPress, ButtonRelease and + * ButtonMotion events. */ +int +discard_window_events ( Window w, long event_mask ) +{ + XEvent e; + int count; + + XSync ( dpy, 0 ); + for( count = 0; XCheckWindowEvent ( dpy, w, event_mask, &e ); count++ ) { + StashEventTime ( &e ); + } + + return count; +} + +Window +create_pan_frame( int x, int y, int width, int height, + unsigned int valuemask, XSetWindowAttributes *attributes ) +{ + return XCreateWindow ( dpy, mscreen->xroot, + x, y, width, height, + 0, /* no border */ + CopyFromParent, InputOnly, CopyFromParent, + valuemask, attributes ); +} + + + +Bool +has_neighbor( MetaMotionDirection direction ) +{ + MetaWorkspace *flipto = meta_workspace_get_neighbor( mscreen->active_workspace, + direction); + if( flipto != NULL && flipto != mscreen->active_workspace ) { + return True; + } + return False; +} + +/**************************************************************************** + * + * Records the time of the last processed event. Used in XSetInputFocus + * + ****************************************************************************/ +#define CLOCK_SKEW_MS 30000 /* ms */ +Bool +StashEventTime ( XEvent * ev ) +{ + Time NewTimestamp = CurrentTime; + + switch ( ev->type ) { + case KeyPress: + case KeyRelease: + NewTimestamp = ev->xkey.time; + break; + case ButtonPress: + case ButtonRelease: + NewTimestamp = ev->xbutton.time; + break; + case MotionNotify: + NewTimestamp = ev->xmotion.time; + break; + case EnterNotify: + case LeaveNotify: + NewTimestamp = ev->xcrossing.time; + break; + case PropertyNotify: + NewTimestamp = ev->xproperty.time; + break; + case SelectionClear: + NewTimestamp = ev->xselectionclear.time; + break; + case SelectionRequest: + NewTimestamp = ev->xselectionrequest.time; + break; + case SelectionNotify: + NewTimestamp = ev->xselection.time; + break; + default: + return False; + } + /* Only update if the new timestamp is later than the old one, or + * if the new one is from a time at least 30 seconds earlier than the + * old one (in which case the system clock may have changed) */ + if( NewTimestamp > lastTimestamp || + lastTimestamp - NewTimestamp > CLOCK_SKEW_MS ) + lastTimestamp = NewTimestamp; + return True; +} + +#undef CLOCK_SKEW_MS Common subdirectories: metacity-2.5.2-base/src/themes and metacity-2.5.2-patch/src/themes Common subdirectories: metacity-2.5.2-base/src/tools and metacity-2.5.2-patch/src/tools diff -uN metacity-2.5.2-base/src/window.c metacity-2.5.2-patch/src/window.c --- metacity-2.5.2-base/src/window.c 2003-05-20 12:27:15.000000000 -0400 +++ metacity-2.5.2-patch/src/window.c 2003-08-30 14:56:35.000000000 -0400 @@ -114,7 +114,7 @@ static void meta_window_update_icon_now (MetaWindow *window); void meta_window_unqueue_update_icon (MetaWindow *window); void meta_window_flush_update_icon (MetaWindow *window); - +void meta_flip_raise_frames (void); static void meta_window_apply_session_info (MetaWindow *window, const MetaWindowSessionInfo *info); @@ -3284,6 +3284,7 @@ "Raising window %s\n", window->desc); meta_stack_raise (window->screen->stack, window); + meta_flip_raise_frames(); } void Common subdirectories: metacity-2.5.2-base/src/wm-tester and metacity-2.5.2-patch/src/wm-tester diff -uN metacity-2.5.2-base/src/workspace.c metacity-2.5.2-patch/src/workspace.c --- metacity-2.5.2-base/src/workspace.c 2003-02-23 12:09:46.000000000 -0500 +++ metacity-2.5.2-patch/src/workspace.c 2003-08-30 14:56:35.000000000 -0400 @@ -27,7 +27,7 @@ #include void meta_workspace_queue_calc_showing (MetaWorkspace *workspace); - +void meta_flip_update_frames ( void ); static void set_active_space_hint (MetaScreen *screen); MetaWorkspace* @@ -220,6 +220,7 @@ meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n"); meta_screen_focus_default_window (workspace->screen, NULL); + meta_flip_update_frames(); } int