Binary files DesktopManager/.DS_Store and DesktopManager-patched/.DS_Store differ
diff -ur DesktopManager/CodeInjection/mach_inject.c DesktopManager-patched/CodeInjection/mach_inject.c
--- DesktopManager/CodeInjection/mach_inject.c	2005-05-02 15:30:46.000000000 -0700
+++ DesktopManager-patched/CodeInjection/mach_inject.c	2007-07-18 23:47:20.000000000 -0700
@@ -1,31 +1,47 @@
-/****************************************************************************************
-	mach_inject.c $Revision: 1.1 $
-	
-	Copyright (c) 2003 Red Shed Software. All rights reserved.
-	by Jonathan 'Wolf' Rentzsch (jon * redshed * net)
-	
-	************************************************************************************/
+ /*******************************************************************************
+	mach_inject.c
+		Copyright (c) 2003-2005 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+		Some rights reserved: <http://creativecommons.org/licenses/by/2.0/>
 
-#include	<mach-o/dyld.h>
-#include	<mach-o/getsect.h>
-#include	<mach/mach.h>
-#include	<sys/stat.h>
-#include	<mach/mach_init.h>
-
-#include	<Carbon/Carbon.h>
+	***************************************************************************/
 
 #include	"mach_inject.h"
 
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+#include <mach/mach.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <assert.h>
+#include <stdlib.h> // for malloc()
+#include <stdio.h>  // for printf()
+#include <mach-o/fat.h> // for fat structure decoding
+#include <mach-o/arch.h> // to know which is local arch
+#include <fcntl.h> // for open/close
+// for mmap()
+#include <sys/types.h>
+#include <sys/mman.h>
+
 #ifndef	COMPILE_TIME_ASSERT( exp )
 	#define COMPILE_TIME_ASSERT( exp ) { switch (0) { case 0: case (exp):; } }
 #endif
-#define ASSERT_CAST( CAST_TO, CAST_FROM )	COMPILE_TIME_ASSERT( sizeof(CAST_TO)==sizeof(CAST_FROM) )
+#define ASSERT_CAST( CAST_TO, CAST_FROM ) \
+	COMPILE_TIME_ASSERT( sizeof(CAST_TO)==sizeof(CAST_FROM) )
 
-/****************************************************************************************
+#if defined(__i386__)
+void* fixedUpImageFromImage (
+		const void *image, 
+		unsigned long imageSize, 
+		unsigned int jumpTableOffset, 
+		unsigned int jumpTableSize,
+		ptrdiff_t fixUpOffset);
+#endif /* __i386__ */
+
+/*******************************************************************************
 *	
 *	Interface
 *	
-****************************************************************************************/
+*******************************************************************************/
 #pragma mark	-
 #pragma mark	(Interface)
 
@@ -35,60 +51,79 @@
 		const void				*paramBlock,
 		size_t					paramSize,
 		pid_t					targetProcess,
-		vm_size_t				stackSize ) {
-	;//assertCodePtr( threadEntry );
-	;//assertPtrIfNotNull( paramBlock );
-	;//assertPositive( targetProcess );
-	;//assertIsTrue( stackSize == 0 || stackSize > 1024 );
+		vm_size_t				stackSize )
+{
+	assert( threadEntry );
+	assert( targetProcess > 0 );
+	assert( stackSize == 0 || stackSize > 1024 );
 	
 	//	Find the image.
 	const void		*image;
 	unsigned long	imageSize;
-	mach_error_t	err = machImageForPointer( threadEntry, &image, &imageSize );
-	
+	unsigned int	jumpTableOffset;
+	unsigned int	jumpTableSize;
+	mach_error_t	err = machImageForPointer( threadEntry, &image, &imageSize, &jumpTableOffset, &jumpTableSize );
+
 	//	Initialize stackSize to default if requested.
 	if( stackSize == 0 )
-		/** @bug We only want an 8K default, fix the plop-in-the-middle code below. */
+		/** @bug
+			We only want an 8K default, fix the plop-in-the-middle code below.
+		*/
 		stackSize = 16 * 1024;
 	
 	//	Convert PID to Mach Task ref.
 	mach_port_t	remoteTask = 0;
-	if( !err )
+	if( !err ) {
 		err = task_for_pid( mach_task_self(), targetProcess, &remoteTask );
+#if defined(__i386__)
+		if (err == 5) fprintf(stderr, "Could not access task for pid %d. You probably need to add user to procmod group\n", targetProcess);
+#endif
+	}
 	
-	/** @todo	Would be nice to just allocate one block for both the remote stack
-				*and* the remoteCode (including the parameter data block once that's
-				written.
+	/** @todo
+		Would be nice to just allocate one block for both the remote stack
+		*and* the remoteCode (including the parameter data block once that's
+		written.
 	*/
 	
 	//	Allocate the remoteStack.
-	vm_address_t remoteStack = 0;
+	vm_address_t remoteStack = (vm_address_t)NULL;
 	if( !err )
 		err = vm_allocate( remoteTask, &remoteStack, stackSize, 1 );
 	
 	//	Allocate the code.
-	vm_address_t remoteCode = 0;
+	vm_address_t remoteCode = (vm_address_t)NULL;
 	if( !err )
 		err = vm_allocate( remoteTask, &remoteCode, imageSize, 1 );
 	if( !err ) {
 		ASSERT_CAST( pointer_t, image );
+#if defined (__ppc__) || defined (__ppc64__)
 		err = vm_write( remoteTask, remoteCode, (pointer_t) image, imageSize );
+#elif defined (__i386__)
+		// on intel, jump table use relative jump instructions (jmp), which means
+		// the offset needs to be corrected. We thus copy the image and fix the offset by hand. 
+		ptrdiff_t fixUpOffset = (ptrdiff_t) (image - remoteCode); 
+		void * fixedUpImage = fixedUpImageFromImage(image, imageSize, jumpTableOffset, jumpTableSize, fixUpOffset);
+		err = vm_write( remoteTask, remoteCode, (pointer_t) fixedUpImage, imageSize );
+		free(fixedUpImage);
+#endif
 	}
 	
 	//	Allocate the paramBlock if specified.
-	vm_address_t remoteParamBlock = 0;
+	vm_address_t remoteParamBlock = (vm_address_t)NULL;
 	if( !err && paramBlock != NULL && paramSize ) {
 		err = vm_allocate( remoteTask, &remoteParamBlock, paramSize, 1 );
 		if( !err ) {
 			ASSERT_CAST( pointer_t, paramBlock );
-			err = vm_write( remoteTask, remoteParamBlock, (pointer_t) paramBlock, paramSize );
+			err = vm_write( remoteTask, remoteParamBlock,
+					(pointer_t) paramBlock, paramSize );
 		}
 	}
 	
 	//	Calculate offsets.
 	ptrdiff_t	threadEntryOffset, imageOffset;
 	if( !err ) {
-		;//assertIsWithinRange( threadEntry, image, image+imageSize );
+		//assert( (void*)threadEntry >= image && (void*)threadEntry <= (image+imageSize) );
 		ASSERT_CAST( void*, threadEntry );
 		threadEntryOffset = ((void*) threadEntry) - image;
 		
@@ -98,10 +133,13 @@
 	
 	//	Allocate the thread.
 	thread_act_t remoteThread;
+#if defined (__ppc__) || defined (__ppc64__)
 	if( !err ) {
 		ppc_thread_state_t remoteThreadState;
 		
-		/** @bug Stack math should be more sophisticated than this (ala redzone). */
+		/** @bug
+			Stack math should be more sophisticated than this (ala redzone).
+		*/
 		remoteStack += stackSize / 2;
 		
 		bzero( &remoteThreadState, sizeof(remoteThreadState) );
@@ -126,16 +164,63 @@
 		ASSERT_CAST( unsigned int, 0xDEADBEEF );
 		remoteThreadState.lr = (unsigned int) 0xDEADBEEF;
 		
-		//printf( "remoteCode start: %p\n", (void*) remoteCode );
-		//printf( "remoteCode size: %ld\n", imageSize );
-		//printf( "remoteCode pc: %p\n", (void*) remoteThreadState.srr0 );
-		//printf( "remoteCode end: %p\n", (void*) (((char*)remoteCode)+imageSize) );
+#if 0
+		printf( "remoteCode start: %p\n", (void*) remoteCode );
+		printf( "remoteCode size: %ld\n", imageSize );
+		printf( "remoteCode pc: %p\n", (void*) remoteThreadState.srr0 );
+		printf( "remoteCode end: %p\n",
+			(void*) (((char*)remoteCode)+imageSize) );
 		fflush(0);
+#endif
 		
 		err = thread_create_running( remoteTask, PPC_THREAD_STATE,
 				(thread_state_t) &remoteThreadState, PPC_THREAD_STATE_COUNT,
 				&remoteThread );
 	}
+#elif defined (__i386__)
+	if( !err ) {
+		
+		i386_thread_state_t remoteThreadState;
+		bzero( &remoteThreadState, sizeof(remoteThreadState) );
+			
+		vm_address_t dummy_thread_struct = remoteStack;
+		remoteStack += (stackSize / 2); // this is the real stack
+		// (*) increase the stack, since we're simulating a CALL instruction, which normally pushes return address on the stack
+		remoteStack -= 4;
+		
+#define PARAM_COUNT 4
+#define STACK_CONTENTS_SIZE ((1+PARAM_COUNT) * sizeof(unsigned int))
+		unsigned int stackContents[1 + PARAM_COUNT]; // 1 for the return address and 1 for each param
+		// first entry is return address (see above *)
+		stackContents[0] = 0xDEADBEEF; // invalid return address.
+		// then we push function parameters one by one.
+		stackContents[1] =  imageOffset;
+		stackContents[2] = remoteParamBlock;
+		stackContents[3] = paramSize;
+		// We use the remote stack we allocated as the fake thread struct. We should probably use a dedicated memory zone. 
+		// We don't fill it with 0, vm_allocate did it for us
+		stackContents[4] = dummy_thread_struct; 
+		
+		// push stackContents
+		err = vm_write( remoteTask, remoteStack,
+						(pointer_t) stackContents, STACK_CONTENTS_SIZE);
+		
+		// set remote Program Counter
+		remoteThreadState.eip = (unsigned int) (remoteCode);
+		remoteThreadState.eip += threadEntryOffset;  
+		
+		// set remote Stack Pointer
+		ASSERT_CAST( unsigned int, remoteStack );
+		remoteThreadState.esp = (unsigned int) remoteStack;
+		
+		// create thread and launch it
+		err = thread_create_running( remoteTask, i386_THREAD_STATE,
+									 (thread_state_t) &remoteThreadState, i386_THREAD_STATE_COUNT,
+									 &remoteThread );
+	}
+#else
+#error architecture not supported
+#endif
 	
 	if( err ) {
 		if( remoteParamBlock )
@@ -153,24 +238,34 @@
 machImageForPointer(
 		const void *pointer,
 		const void **image,
-		unsigned long *size ) {
-	;//assertCodePtr( pointer );
-	;//assertPtr( image );
-	;//assertPtr( size );
+		unsigned long *size,
+		unsigned int *jumpTableOffset,
+		unsigned int *jumpTableSize )
+{
+	assert( pointer );
+	assert( image );
+	assert( size );
 	
 	unsigned long p = (unsigned long) pointer;
 	
+	if (jumpTableOffset && jumpTableSize) {
+		*jumpTableOffset = 0;
+		*jumpTableSize = 0;
+	}
+	
 	unsigned long imageIndex, imageCount = _dyld_image_count();
 	for( imageIndex = 0; imageIndex < imageCount; imageIndex++ ) {
-		struct mach_header *header = (struct mach_header*) _dyld_get_image_header( imageIndex );
-		const struct section *section = getsectbynamefromheader( header, SEG_TEXT, SECT_TEXT );
+		const struct mach_header *header = _dyld_get_image_header( imageIndex );
+		const struct section *section = getsectbynamefromheader( header,
+																	SEG_TEXT,
+																	SECT_TEXT );
 		long start = section->addr + _dyld_get_image_vmaddr_slide( imageIndex );
 		long stop = start + section->size;
 		if( p >= start && p <= stop ) {
-			//	It is truely insane we have to stat() the file system in order to
-			//	discover the size of an in-memory data structure.
-			char *imageName = (char*) _dyld_get_image_name( imageIndex );
-			;//assertPath( imageName );
+			//	It is truely insane we have to stat() the file system in order
+			//	to discover the size of an in-memory data structure.
+			const char *imageName = _dyld_get_image_name( imageIndex );
+			assert( imageName );
 			struct stat sb;
 			if( stat( imageName, &sb ) )
 				return unix_err( errno );
@@ -181,10 +276,86 @@
 			if( size ) {
 				;//assertUInt32( st_size );
 				*size = sb.st_size;
+				
+				// needed for Universal binaries. Check if file is fat and get image size from there.
+				int fd = open (imageName, O_RDONLY);
+				size_t mapSize = *size;
+				char * fileImage = mmap (NULL, mapSize, PROT_READ, MAP_FILE, fd, 0);
+				
+				struct fat_header* fatHeader = (struct fat_header *)fileImage;
+				if (fatHeader->magic == OSSwapBigToHostInt32(FAT_MAGIC)) {
+					//printf("This is a fat binary\n");
+					uint32_t archCount = OSSwapBigToHostInt32(fatHeader->nfat_arch);
+					
+					NXArchInfo const *localArchInfo = NXGetLocalArchInfo();
+					
+					struct fat_arch* arch = (struct fat_arch *)(fileImage + sizeof(struct fat_header));
+					struct fat_arch* matchingArch = NULL;
+					
+					int archIndex = 0;
+					for (archIndex = 0; archIndex < archCount; archIndex++) {
+						cpu_type_t cpuType = OSSwapBigToHostInt32(arch[archIndex].cputype);
+						cpu_subtype_t cpuSubtype = OSSwapBigToHostInt32(arch[archIndex].cpusubtype);
+						
+						if (localArchInfo->cputype == cpuType) {
+							matchingArch = arch + archIndex;
+							if (localArchInfo->cpusubtype == cpuSubtype) break;
+						}
+					}
+					
+					if (matchingArch) {
+						*size = OSSwapBigToHostInt32(matchingArch->size);
+						//printf ("found arch-specific size : %p\n", *size);
+					}
+				}
+				
+				munmap (fileImage, mapSize);
+				close (fd);
+			}
+			if (jumpTableOffset && jumpTableSize) {
+				const struct section * jumpTableSection = getsectbynamefromheader( header,
+																				   "__IMPORT",
+																				   "__jump_table" );
+				if (jumpTableSection) {
+					*jumpTableOffset = jumpTableSection->offset;
+					*jumpTableSize = jumpTableSection->size;
+				}
 			}
 			return err_none;
 		}
 	}
 	
 	return err_threadEntry_image_not_found;
-}
\ No newline at end of file
+}
+
+#if defined(__i386__)
+void* fixedUpImageFromImage (
+		const void *image, 
+		unsigned long imageSize, 
+		unsigned int jumpTableOffset, 
+		unsigned int jumpTableSize, 
+		ptrdiff_t fixUpOffset)
+{
+	// first copy the full image
+	void *fixedUpImage = (void *) malloc ((size_t)imageSize);
+	bcopy(image, fixedUpImage, imageSize);
+	
+	// address of jump table in copied image
+	void *jumpTable = fixedUpImage + jumpTableOffset;
+	// each JMP instruction is 5 bytes (E9 xx xx xx xx) where E9 is the opcode for JMP
+	int jumpTableCount = jumpTableSize / 5;
+	
+	// skip first "E9"
+	jumpTable++;
+	
+	int entry=0;
+	for (entry = 0; entry < jumpTableCount; entry++) {
+		unsigned int jmpValue = *((unsigned int *)jumpTable);
+		jmpValue += fixUpOffset;
+		*((unsigned int *)jumpTable) = jmpValue;
+		jumpTable+=5;
+	}
+	
+	return fixedUpImage;
+}
+#endif /* __i386__ */
\ No newline at end of file
Only in DesktopManager-patched/CodeInjection: mach_inject.c.orig
Only in DesktopManager-patched/CodeInjection: mach_inject.c.rej
diff -ur DesktopManager/CodeInjection/mach_inject.h DesktopManager-patched/CodeInjection/mach_inject.h
--- DesktopManager/CodeInjection/mach_inject.h	2004-07-09 05:54:33.000000000 -0700
+++ DesktopManager-patched/CodeInjection/mach_inject.h	2007-07-18 23:47:23.000000000 -0700
@@ -1,20 +1,20 @@
-/****************************************************************************************
-	mach_inject.h $Revision: 1.1 $
-	
-	Copyright (c) 2003 Red Shed Software. All rights reserved.
-	by Jonathan 'Wolf' Rentzsch (jon * redshed * net)
-	
-	************************************************************************************/
+/*******************************************************************************
+	mach_inject.h
+		Copyright (c) 2003-2005 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+		Some rights reserved: <http://creativecommons.org/licenses/by/2.0/>
+
+	***************************************************************************/
 	
-/************************************************************************************//**
+/***************************************************************************//**
 	@mainpage	mach_inject
-	@author		Jonathan 'Wolf' Rentzsch (jon * redshed * net)
+	@author		Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
 	
-	This package, coded in C to the Mach API, allows you to "inject" code into an
-	arbitrary process. "Injection" means both 1) copying over the necessary code into the
-	target's address space and 2) remotely creating a new thread to execute the code.
+	This package, coded in C to the Mach API, allows you to "inject" code into
+	an arbitrary process. "Injection" means both 1) copying over the necessary
+	code into the target's address space and 2) remotely creating a new thread
+	to execute the code.
 
-	************************************************************************************/
+	***************************************************************************/
 
 #ifndef		_mach_inject_
 #define		_mach_inject_
@@ -22,28 +22,35 @@
 #include <sys/types.h>
 #include <mach/error.h>
 #include <mach/vm_types.h>
+#include <stddef.h> // for ptrdiff_t
+
+#ifdef	__cplusplus
+	extern	"C"	{
+#endif
 
 #define	err_threadEntry_image_not_found			(err_local|1)
 
 #define	INJECT_ENTRY		injectEntry
 #define	INJECT_ENTRY_SYMBOL	"injectEntry"
 
-typedef	void	(*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock, size_t paramSize );
+typedef	void	(*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock,
+				size_t paramSize, void* dummy_pthread_data );
 	
-/************************************************************************************//**
+/***************************************************************************//**
 	Starts executing threadEntry in a new thread in the process specified by
 	targetProcess.
 	
-	@param	threadEntry		->	Required pointer to injected thread's entry point.
-	@param	paramBlock		->	Optional pointer to block of memory to pass to the
-								injected thread.
+	@param	threadEntry		->	Required pointer to injected thread's entry
+								point.
+	@param	paramBlock		->	Optional pointer to block of memory to pass to
+								the injected thread.
 	@param	paramSize		->	Optional size of paramBlock.
 	@param	targetProcess	->	Required target process ID.
-	@param	stackSize		->	Optional stack size of threadEntry's thread. Set to zero
-								for default (currently 8K usable).
+	@param	stackSize		->	Optional stack size of threadEntry's thread. Set
+								to zero for default (currently 8K usable).
 	@result					<-	mach_error_t
 
-	************************************************************************************/
+	***************************************************************************/
 
 	mach_error_t
 mach_inject(
@@ -53,20 +60,28 @@
 		pid_t					targetProcess,
 		vm_size_t				stackSize );
 
-/************************************************************************************//**
+/***************************************************************************//**
 	Given a pointer, returns its Mach-O image and image size.
 	
-	@param	pointer	->	Required pointer.
-	@param	image	<-	Optional returned pointer to image (really a mach_header).
-	@param	size	<-	Optional returned size of the image.
-	@result			<-	mach_error_t
+	@param	pointer			->	Required pointer.
+	@param	image			<-	Optional returned pointer to image (really a
+								mach_header).
+	@param	size			<-	Optional returned size of the image.
+	@param  jumpTableOffset <-  Optional returned offset of jump table within image (useful on intel)
+	@param  jumpTableSize	<-  Optional returned size of jump table (useful on intel)
+	@result					<-	mach_error_t
 	
-	************************************************************************************/
+	***************************************************************************/
 
 	mach_error_t
 machImageForPointer(
 		const void *pointer,
 		const void **image,
-		unsigned long *size );
-
+		unsigned long *size,
+		unsigned int *jumpTableOffset,
+		unsigned int *jumpTableSize );
+
+#ifdef	__cplusplus
+	}
+#endif
 #endif	//	_mach_inject_
\ No newline at end of file
Only in DesktopManager-patched/CodeInjection: mach_inject.h.orig
Only in DesktopManager-patched/CodeInjection: mach_inject.h.rej
diff -ur DesktopManager/Core/DMController.m DesktopManager-patched/Core/DMController.m
--- DesktopManager/Core/DMController.m	2004-07-12 09:05:39.000000000 -0700
+++ DesktopManager-patched/Core/DMController.m	2007-07-18 23:40:51.000000000 -0700
@@ -202,6 +202,16 @@
         object: self];
 }
 
+- (void) upperDesktop: (id) sender {
+    [[NSNotificationCenter defaultCenter] postNotificationName: NOTIFICATION_UPPERWORKSPACE
+        object: self];
+}
+
+- (void) lowerDesktop: (id) sender {
+    [[NSNotificationCenter defaultCenter] postNotificationName: NOTIFICATION_LOWERWORKSPACE
+        object: self];
+}
+
 - (void) showNotificationWindow {
 	if(!notificationWindow) {
 		// Create a notification window.
diff -ur DesktopManager/Core/ForeignWindow.m DesktopManager-patched/Core/ForeignWindow.m
--- DesktopManager/Core/ForeignWindow.m	2005-05-02 15:34:20.000000000 -0700
+++ DesktopManager-patched/Core/ForeignWindow.m	2007-07-18 23:40:51.000000000 -0700
@@ -438,13 +438,46 @@
     return psn;
 }
 
+extern CGError CGSGetCurrentCursorLocation(CGSConnection connection, CGPoint* point);
+
 - (void) focusOwner
 {
-    OSStatus retVal;
+	OSStatus retVal;
+
+	ProcessSerialNumber current;
+
+    if(retVal = GetFrontProcess(&current)) {
+        NSLog(@"Error getting front process: %i\n", (int)retVal);
+        return;
+        }
+
     ProcessSerialNumber psn = [self ownerPSN];
-    if(retVal = SetFrontProcess(&psn)) {
-        NSLog(@"Error focusing owner: %i\n", (int)retVal);
-    }
+    Boolean same;
+    SameProcess(&psn, &current, &same);
+    
+    if ( ! same )
+	    if(retVal = SetFrontProcess(&psn)) {
+    	    NSLog(@"Error focusing owner: %i\n", (int)retVal);
+        	return;
+	        }	
+
+	// Hack to activate X11 windows [robin]
+	NSString* owner = [self ownerName];
+	NSLog(owner);
+
+    if ( [owner compare:@"X11"] == 0 ) {	
+	    CGPoint loc;
+    	if(CGSGetCurrentCursorLocation(_CGSDefaultConnection(), &loc) != kCGErrorSuccess) {
+        	NSLog(@"Cannot get cursor location");
+            return;
+            }
+
+		CGSetLocalEventsSuppressionInterval(0.0); 
+	    loc.x += 1;
+	    CGPostMouseEvent(loc, TRUE, 1, 0);
+	    loc.x -= 1;
+	    CGPostMouseEvent(loc, TRUE, 1, 0);
+        }
 }
 
 
diff -ur DesktopManager/Core/WorkspaceController.m DesktopManager-patched/Core/WorkspaceController.m
--- DesktopManager/Core/WorkspaceController.m	2004-07-12 06:33:14.000000000 -0700
+++ DesktopManager-patched/Core/WorkspaceController.m	2007-07-18 23:40:51.000000000 -0700
@@ -18,6 +18,7 @@
 
 #import "DesktopNamesPreferences.h"
 #import "DesktopManager.h"
+#import "../Plugins/DesktopPager/DesktopPagerController.h"
 
 #import <AvailabilityMacros.h>
 #import <ApplicationServices/ApplicationServices.h>
@@ -67,6 +68,17 @@
             name: NOTIFICATION_NEXTWORKSPACE
             object: nil
         ];
+        
+        [[NSNotificationCenter defaultCenter] addObserver: self
+            selector: @selector(selectLowerWorkspace)
+            name: NOTIFICATION_LOWERWORKSPACE
+            object: nil
+        ];
+        [[NSNotificationCenter defaultCenter] addObserver: self
+            selector: @selector(selectUpperWorkspace)
+            name: NOTIFICATION_UPPERWORKSPACE
+            object: nil
+        ];
         // Register an interest in window warp hotkeys
         [[NSNotificationCenter defaultCenter] addObserver: self
             selector: @selector(warpToPreviousWorkspace)
@@ -79,6 +91,16 @@
             object: nil
         ];
         [[NSNotificationCenter defaultCenter] addObserver: self
+            selector: @selector(warpToLowerWorkspace)
+            name: NOTIFICATION_WARPTOLOWERWORKSPACE
+            object: nil
+        ];
+        [[NSNotificationCenter defaultCenter] addObserver: self
+            selector: @selector(warpToUpperWorkspace)
+            name: NOTIFICATION_WARPTOUPPERWORKSPACE
+            object: nil
+        ];
+        [[NSNotificationCenter defaultCenter] addObserver: self
             selector: @selector(prefsChanged:)
             name: NOTIFICATION_PREFSCHANGED
             object: nil
@@ -315,6 +337,8 @@
 	return option;
 }
 
+extern OSStatus CGSSetActiveWindow(const CGSConnection cid, int flag);
+
 - (void) selectWorkspace: (int)workspace {
     if((workspace < 0) || (workspace >= [self workspaceCount])) {
         NSLog(@"Attempt to switch to invalid workspace %i", workspace);
@@ -350,39 +374,127 @@
 		floatForKey: PREF_DESKTOPSWITCH_DURATION];
     }
 
-	[ws selectWithTransition: transitionNumber option: option duration: duration];
+    [ws selectWithTransition: transitionNumber option: option duration: duration];
+
+	// Auto-focus on new work-space.    
+	ForeignWindow *window = [self windowUnderPointer];
+    if(window) {
+ 	  NSLog(@"setting focus %d", window);
+      [window focusOwner];
+      }
+    else 
+	  NSLog(@"not setting focus");
+
 }
 
 - (void) selectNextWorkspace {
     int cwsi = [self currentWorkspaceIndex];
     if(cwsi == -1) { return; }
-    
-    cwsi++;
-    if(cwsi >= [self workspaceCount]) { cwsi = 0; }
-    if(cwsi < 0) { cwsi = [self workspaceCount]-1; }
-    
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentCol += 1;
+
+    if ( currentCol >= columns )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
     [self selectWorkspace: cwsi];
 }
 
 - (void) selectPreviousWorkspace {
     int cwsi = [self currentWorkspaceIndex];
     if(cwsi == -1) { return; }
-    
-    cwsi--;
-    if(cwsi >= [self workspaceCount]) { cwsi = 0; }
-    if(cwsi < 0) { cwsi = [self workspaceCount]-1; }
-    
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentCol -= 1;
+
+    if ( currentCol < 0 )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
+    [self selectWorkspace: cwsi];
+}
+
+- (void) selectLowerWorkspace {
+    int cwsi = [self currentWorkspaceIndex];
+    if(cwsi == -1) { return; }
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentRow += 1;
+
+    if ( currentRow > [self workspaceCount] )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
+    [self selectWorkspace: cwsi];
+}
+
+- (void) selectUpperWorkspace {
+    int cwsi = [self currentWorkspaceIndex];
+    if(cwsi == -1) { return; }
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentRow -= 1;
+
+    if ( currentRow < 0 )  	  
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
     [self selectWorkspace: cwsi];
 }
 
 - (void) warpToNextWorkspace {
     int cwsi = [self currentWorkspaceIndex];
     if(cwsi == -1) { return; }
-    
-    cwsi++;
-    if(cwsi >= [self workspaceCount]) { cwsi = 0; }
-    if(cwsi < 0) { cwsi = [self workspaceCount]-1; }
-    
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentCol += 1;
+
+    if ( currentCol >= columns )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
+
     Workspace *nextWs = [self workspaceAtIndex: cwsi];
 	ForeignWindow *window = [self windowUnderPointer];
 	if(window && nextWs) {
@@ -394,10 +506,50 @@
 - (void) warpToPreviousWorkspace {
     int cwsi = [self currentWorkspaceIndex];
     if(cwsi == -1) { return; }
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentCol -= 1;
+
+    if ( currentCol < 0 )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
     
-    cwsi--;
-    if(cwsi >= [self workspaceCount]) { cwsi = 0; }
-    if(cwsi < 0) { cwsi = [self workspaceCount]-1; }
+    Workspace *prevWs = [self workspaceAtIndex: cwsi];
+	ForeignWindow *window = [self windowUnderPointer];
+	if(window && prevWs) {
+		[window moveToWorkspace: prevWs];
+		[prevWs selectWithDefaultTransition];
+	}
+}
+
+- (void) warpToLowerWorkspace {
+    int cwsi = [self currentWorkspaceIndex];
+    if(cwsi == -1) { return; }
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentRow += 1;
+
+    if ( currentRow > [self workspaceCount] )    
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
     
     Workspace *prevWs = [self workspaceAtIndex: cwsi];
 	ForeignWindow *window = [self windowUnderPointer];
@@ -407,6 +559,34 @@
 	}
 }
 
+- (void) warpToUpperWorkspace {
+    int cwsi = [self currentWorkspaceIndex];
+    if(cwsi == -1) { return; }
+
+	int numberPagerRows = [[NSUserDefaults standardUserDefaults] 
+		integerForKey: PREF_DESKTOPPAGER_ROWS ];
+
+	int columns = [self workspaceCount] / numberPagerRows;
+    if(columns * numberPagerRows <  [self workspaceCount]) { columns++; }        
+      
+    int currentCol = cwsi % columns;    
+    int currentRow = cwsi / columns;
+
+	currentRow -= 1;
+
+    if ( currentRow < 0 )  	  
+      return;
+      
+    cwsi = currentCol + currentRow * columns;
+
+    Workspace *prevWs = [self workspaceAtIndex: cwsi];
+	ForeignWindow *window = [self windowUnderPointer];
+	if(window && prevWs) {
+		[window moveToWorkspace: prevWs];
+		[prevWs selectWithDefaultTransition];
+	}
+}
+
 - (Workspace*) workspaceAtIndex: (int) index {
     if((index < 0) || (index >= [self workspaceCount])) { return nil; }
     
diff -ur DesktopManager/English.lproj/Localizable.strings DesktopManager-patched/English.lproj/Localizable.strings
--- DesktopManager/English.lproj/Localizable.strings	2004-07-12 08:37:34.000000000 -0700
+++ DesktopManager-patched/English.lproj/Localizable.strings	2007-07-18 23:40:51.000000000 -0700
@@ -2,6 +2,8 @@
 
 SwitchToNextWorkspace = "Switch to Next Desktop";
 SwitchToPrevWorkspace = "Switch to Previous Desktop";
+SwitchToLowerWorkspace = "Switch to Lower Desktop";
+SwitchToUpperWorkspace = "Switch to Upper Desktop";
 ShowOperationsMenu = "Show Operations Window";
 ShowPreferences = "Show Preferences Window";
 SwitchToDesktop1 = "Switch to Desktop 1";
@@ -26,6 +28,8 @@
 CollectMessage = "Should Desktop Manager collect all windows onto one workspace before quitting?";
 WarpToNextWorkspace = "Move Window to Next Desktop";
 WarpToPrevWorkspace = "Move Window to Previous Desktop";
+WarpToLowerWorkspace = "Move Window to Lower Desktop";
+WarpToUpperWorkspace = "Move Window to Upper Desktop";
 RunApplicationMessage = "Desktop Manager encountered an error";
 RunApplicationDefault = "OK";
 RunApplicationInfo = "There was an error attemting to run the '%@' Application. This may be because Desktop Manager couldn't find it.";
@@ -34,4 +38,4 @@
 WindowManipulation = "Window Manipulation";
 DesktopNavigation = "Desktop Navigation";
 MakeSticky = "Put on all desktops";
-MakeUnSticky = "Leave on this desktop";
\ No newline at end of file
+MakeUnSticky = "Leave on this desktop";
diff -ur DesktopManager/HotKeys/HotKeyController.m DesktopManager-patched/HotKeys/HotKeyController.m
--- DesktopManager/HotKeys/HotKeyController.m	2004-07-09 05:54:33.000000000 -0700
+++ DesktopManager-patched/HotKeys/HotKeyController.m	2007-07-18 23:40:52.000000000 -0700
@@ -49,6 +49,18 @@
             nil
         ],
 		[NSMutableDictionary dictionaryWithObjectsAndKeys:
+            [NSNumber numberWithInt: 126], KEYCODE_KEY,
+            [NSNumber numberWithInt: NSCommandKeyMask | NSAlternateKeyMask], MODIFIERS_KEY,
+			NOTIFICATION_UPPERWORKSPACE, NOTIFICATION_KEY,
+            nil
+        ],
+        [NSMutableDictionary dictionaryWithObjectsAndKeys:
+            [NSNumber numberWithInt: 125], KEYCODE_KEY,
+            [NSNumber numberWithInt: NSCommandKeyMask | NSAlternateKeyMask], MODIFIERS_KEY,
+			NOTIFICATION_LOWERWORKSPACE, NOTIFICATION_KEY,
+            nil
+        ],
+		[NSMutableDictionary dictionaryWithObjectsAndKeys:
 			[NSNumber numberWithInt: 18], KEYCODE_KEY,
 			[NSNumber numberWithInt: NSCommandKeyMask | NSAlternateKeyMask], MODIFIERS_KEY,
 			NOTIFICATION_DESKTOP1, NOTIFICATION_KEY,
@@ -125,6 +137,18 @@
 			[NSNumber numberWithInt: NSCommandKeyMask | NSControlKeyMask], MODIFIERS_KEY,
 			NOTIFICATION_WARPTOPREVWORKSPACE, NOTIFICATION_KEY,
 			nil
+        ],
+		[NSMutableDictionary dictionaryWithObjectsAndKeys:
+			[NSNumber numberWithInt: 126], KEYCODE_KEY,
+			[NSNumber numberWithInt: NSCommandKeyMask | NSControlKeyMask], MODIFIERS_KEY,
+			NOTIFICATION_WARPTOUPPERWORKSPACE, NOTIFICATION_KEY,
+			nil
+		],
+		[NSMutableDictionary dictionaryWithObjectsAndKeys:
+			[NSNumber numberWithInt: 125], KEYCODE_KEY,
+			[NSNumber numberWithInt: NSCommandKeyMask | NSControlKeyMask], MODIFIERS_KEY,
+			NOTIFICATION_WARPTOLOWERWORKSPACE, NOTIFICATION_KEY,
+			nil
 		],
 		[NSMutableDictionary dictionaryWithObjectsAndKeys:
 			[NSNumber numberWithInt: 31], KEYCODE_KEY,
diff -ur DesktopManager/Include/Notifications.h DesktopManager-patched/Include/Notifications.h
--- DesktopManager/Include/Notifications.h	2004-07-12 06:47:24.000000000 -0700
+++ DesktopManager-patched/Include/Notifications.h	2007-07-18 23:40:52.000000000 -0700
@@ -27,8 +27,12 @@
 
 #define NOTIFICATION_NEXTWORKSPACE          @"SwitchToNextWorkspace"
 #define NOTIFICATION_PREVWORKSPACE          @"SwitchToPrevWorkspace"
+#define NOTIFICATION_UPPERWORKSPACE         @"SwitchToUpperWorkspace"
+#define NOTIFICATION_LOWERWORKSPACE         @"SwitchToLowerWorkspace"
 #define NOTIFICATION_WARPTONEXTWORKSPACE	@"WarpToNextWorkspace"
 #define NOTIFICATION_WARPTOPREVWORKSPACE	@"WarpToPrevWorkspace"
+#define NOTIFICATION_WARPTOUPPERWORKSPACE	@"WarpToUpperWorkspace"
+#define NOTIFICATION_WARPTOLOWERWORKSPACE	@"WarpToLowerWorkspace"
 #define NOTIFICATION_SHOWPREFS              @"ShowPreferences"
 #define NOTIFICATION_DESKTOP1               @"SwitchToDesktop1"
 #define NOTIFICATION_DESKTOP2               @"SwitchToDesktop2"
diff -ur DesktopManager/Include/WorkspaceController.h DesktopManager-patched/Include/WorkspaceController.h
--- DesktopManager/Include/WorkspaceController.h	2004-07-12 05:03:40.000000000 -0700
+++ DesktopManager-patched/Include/WorkspaceController.h	2007-07-18 23:40:52.000000000 -0700
@@ -41,6 +41,8 @@
 - (void) selectWorkspace: (int) workspace;
 - (void) selectNextWorkspace;
 - (void) selectPreviousWorkspace;
+- (void) selectUpperWorkspace;
+- (void) selectLowerWorkspace;
 - (int) workspaceCount;
 - (void) switchToWorkspaceForApplication: (ProcessSerialNumber) frontPSN;
 - (Workspace*) workspaceAtIndex: (int) index;
diff -ur DesktopManager/Info.plist DesktopManager-patched/Info.plist
--- DesktopManager/Info.plist	2005-05-02 15:29:17.000000000 -0700
+++ DesktopManager-patched/Info.plist	2007-07-18 23:40:52.000000000 -0700
@@ -17,7 +17,7 @@
 	<key>CFBundleSignature</key>
 	<string>rjw1</string>
 	<key>CFBundleVersion</key>
-	<string>0.5.3</string>
+	<string>0.5.3-rs</string>
 	<key>LSUIElement</key>
 	<true/>
 	<key>NSAppleScriptEnabled</key>
diff -ur DesktopManager/Plugins/ActiveEdges/ActiveEdgesController.m DesktopManager-patched/Plugins/ActiveEdges/ActiveEdgesController.m
--- DesktopManager/Plugins/ActiveEdges/ActiveEdgesController.m	2004-07-09 05:56:32.000000000 -0700
+++ DesktopManager-patched/Plugins/ActiveEdges/ActiveEdgesController.m	2007-07-18 23:40:52.000000000 -0700
@@ -42,22 +42,46 @@
 	NSRect screenFrame = [wsController overallScreenFrame];
 	CGPoint newLoc;
 
-	if(edge == LeftEdge) {
-		[wsController selectPreviousWorkspace];
-		if([[NSUserDefaults standardUserDefaults] boolForKey:
+    if(edge == LeftEdge) {
+      	Workspace *oldWorkspace = [wsController currentWorkspace];
+        [wsController selectPreviousWorkspace];
+        if( [wsController currentWorkspace] != oldWorkspace && 
+            [[NSUserDefaults standardUserDefaults] boolForKey:
 			PREF_ACTIVEEDGES_WARPMOUSE]) {
 			newLoc.x = screenFrame.origin.x + screenFrame.size.width - 5;
 			newLoc.y = screenFrame.size.height - mouseLoc.y;
 			CGWarpMouseCursorPosition(newLoc);
 		}
 	} else if(edge == RightEdge) {
+      	Workspace *oldWorkspace = [wsController currentWorkspace];
 		[wsController selectNextWorkspace];
-		if([[NSUserDefaults standardUserDefaults] boolForKey:
+        if( [wsController currentWorkspace] != oldWorkspace && 
+		    [[NSUserDefaults standardUserDefaults] boolForKey:
 			PREF_ACTIVEEDGES_WARPMOUSE]) {
 			newLoc.x = screenFrame.origin.x + 5;
 			newLoc.y = screenFrame.size.height - mouseLoc.y;
 			CGWarpMouseCursorPosition(newLoc);
 		}
+	} else if(edge == TopEdge) {
+      	Workspace *oldWorkspace = [wsController currentWorkspace];
+		[wsController selectUpperWorkspace];
+        if( [wsController currentWorkspace] != oldWorkspace && 
+		    [[NSUserDefaults standardUserDefaults] boolForKey:
+			PREF_ACTIVEEDGES_WARPMOUSE]) {
+			newLoc.x = mouseLoc.x;
+			newLoc.y = screenFrame.size.height - 5;
+			CGWarpMouseCursorPosition(newLoc);
+		}
+	} else if(edge == BottomEdge) {
+      	Workspace *oldWorkspace = [wsController currentWorkspace];
+		[wsController selectLowerWorkspace];
+        if( [wsController currentWorkspace] != oldWorkspace && 
+		    [[NSUserDefaults standardUserDefaults] boolForKey:
+			PREF_ACTIVEEDGES_WARPMOUSE]) {
+			newLoc.x = mouseLoc.x;
+			newLoc.y = 5;
+			CGWarpMouseCursorPosition(newLoc);
+		}
 	}
 	
 	waitingForExit = YES;
diff -ur DesktopManager/Plugins/DesktopPager/DesktopPagerController.m DesktopManager-patched/Plugins/DesktopPager/DesktopPagerController.m
--- DesktopManager/Plugins/DesktopPager/DesktopPagerController.m	2004-07-09 07:05:24.000000000 -0700
+++ DesktopManager-patched/Plugins/DesktopPager/DesktopPagerController.m	2007-07-18 23:40:52.000000000 -0700
@@ -164,7 +164,7 @@
 
 - (void) workspaceSelected {
 	if([pagerWindow isVisible]) {
-		// [pagerWindow orderOut: self];
+		[pagerWindow orderOut: self];
 		[pagerWindow orderFront: self];
 	}
 }
diff -ur DesktopManager/Utility/MouseWatcher.h DesktopManager-patched/Utility/MouseWatcher.h
--- DesktopManager/Utility/MouseWatcher.h	2004-07-12 08:56:57.000000000 -0700
+++ DesktopManager-patched/Utility/MouseWatcher.h	2007-07-18 23:40:52.000000000 -0700
@@ -25,7 +25,8 @@
 	None = 0,
 	BottomEdge = 1,
 	LeftEdge,
-	RightEdge
+	RightEdge,
+    TopEdge
 } MouseWatcherEdge;
 
 @interface MouseWatcher : NSObject {
diff -ur DesktopManager/Utility/MouseWatcher.m DesktopManager-patched/Utility/MouseWatcher.m
--- DesktopManager/Utility/MouseWatcher.m	2004-07-12 08:57:56.000000000 -0700
+++ DesktopManager-patched/Utility/MouseWatcher.m	2007-07-18 23:40:52.000000000 -0700
@@ -51,16 +51,22 @@
 }
 
 - (MouseWatcherEdge) _edgeContainingPoint: (CGPoint) loc {
-	if((loc.x >= screenRect.origin.x) && (loc.x <= screenRect.origin.x + 3)) {
+	if((loc.x >= screenRect.origin.x) && (loc.x <= screenRect.origin.x + 1)) {
 		return LeftEdge;
 	}
 	if((loc.x <= screenRect.origin.x + screenRect.size.width) && 
-	   (loc.x >= screenRect.origin.x + screenRect.size.width - 3)) {
+	   (loc.x >= screenRect.origin.x + screenRect.size.width - 1)) {
 		return RightEdge;
 	}
 	if((loc.y <= screenRect.origin.y + screenRect.size.height) && 
-	   (loc.y >= screenRect.origin.y + screenRect.size.height - 3)) {
-		return BottomEdge;
+	   (loc.y >= screenRect.origin.y + screenRect.size.height - 1)) {
+       	if ( screenRect.origin.x + loc.x <= 100 || screenRect.origin.x + loc.x >= screenRect.size.width - 100 )
+			return BottomEdge;
+	}
+	if((loc.y <= screenRect.origin.y + 1) && 
+       (loc.y >= screenRect.origin.y)) {
+       	if ( screenRect.origin.x + loc.x >= 1000 )
+			return TopEdge;
 	}
 	
 	return None;
Only in DesktopManager-patched/: build
