This commit is contained in:
rhp 2001-07-12 05:53:56 +00:00
parent 71d3333d4d
commit 93b7bd2c81
9 changed files with 429 additions and 12 deletions

View File

@ -1290,6 +1290,10 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_button = button;
display->grab_root_x = root_x;
display->grab_root_y = root_y;
display->grab_initial_window_pos = window->rect;
meta_window_get_position (display->grab_window,
&display->grab_initial_window_pos.x,
&display->grab_initial_window_pos.y);
meta_verbose ("Grab op %d on window %s successful\n",
display->grab_op, display->grab_window->desc);

View File

@ -129,6 +129,7 @@ struct _MetaDisplay
gulong grab_mask;
guint grab_have_pointer : 1;
guint grab_have_keyboard : 1;
MetaRectangle grab_initial_window_pos;
};
gboolean meta_display_open (const char *name);

View File

@ -24,6 +24,7 @@
#include "errors.h"
#include "ui.h"
#include "frame.h"
#include "place.h"
#include <X11/keysym.h>
@ -401,47 +402,84 @@ meta_display_process_key_event (MetaDisplay *display,
int x, y;
int incr;
gboolean smart_snap;
int edge;
if (event->type == KeyRelease)
return; /* don't care about releases */
if (window == NULL)
meta_bug ("NULL window while META_GRAB_OP_MOVING\n");
meta_window_get_position (window, &x, &y);
smart_snap =
(event->xkey.state & ControlMask) != 0 &&
(event->xkey.state & ShiftMask) != 0;
smart_snap = (event->xkey.state & ShiftMask) != 0;
/* FIXME replace LARGE_INCREMENT with intelligent snapping */
#define SMALL_INCREMENT 1
#define NORMAL_INCREMENT 10
#define LARGE_INCREMENT 100
if (smart_snap)
incr = LARGE_INCREMENT;
incr = 0;
else if (event->xkey.state & ControlMask)
incr = SMALL_INCREMENT;
else
incr = NORMAL_INCREMENT;
/* When moving by increments, we still snap to edges if the move
* to the edge is smaller than the increment. This is because
* Shift + arrow to snap is sort of a hidden feature. This way
* people using just arrows shouldn't get too frustrated.
*/
switch (keysym)
{
case XK_Up:
case XK_KP_Up:
edge = meta_window_find_next_horizontal_edge (window, FALSE);
y -= incr;
if (smart_snap || ((edge > y) && ABS (edge - y) < incr))
y = edge;
handled = TRUE;
break;
case XK_Down:
case XK_KP_Down:
edge = meta_window_find_next_horizontal_edge (window, TRUE);
y += incr;
if (smart_snap || ((edge < y) && ABS (edge - y) < incr))
y = edge;
handled = TRUE;
break;
case XK_Left:
case XK_KP_Left:
edge = meta_window_find_next_vertical_edge (window, FALSE);
x -= incr;
if (smart_snap || ((edge > x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Right:
case XK_KP_Right:
edge = meta_window_find_next_vertical_edge (window, TRUE);
x += incr;
if (smart_snap || ((edge < x) && ABS (edge - x) < incr))
x = edge;
handled = TRUE;
break;
case XK_Escape:
/* End move and restore to original position */
meta_window_move_resize (display->grab_window,
display->grab_initial_window_pos.x,
display->grab_initial_window_pos.y,
display->grab_initial_window_pos.width,
display->grab_initial_window_pos.height);
break;
default:
break;
}

View File

@ -23,6 +23,7 @@
#include "workspace.h"
#include <gdk/gdkregion.h>
#include <math.h>
#include <stdlib.h>
static gint
northwestcmp (gconstpointer a, gconstpointer b)
@ -304,3 +305,351 @@ meta_window_place (MetaWindow *window,
*new_x = x;
*new_y = y;
}
/* These are used while moving or resizing to "snap" to useful
* places; the return value is the x/y position of the window to
* be snapped to the given edge.
*
* They only use edges on the current workspace, since things
* would be weird otherwise.
*/
static GSList*
get_windows_on_same_workspace (MetaWindow *window,
int *n_windows)
{
GSList *windows;
GSList *all_windows;
GSList *tmp;
int i;
windows = NULL;
i = 0;
all_windows = meta_display_list_windows (window->display);
tmp = all_windows;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
if (!w->minimized &&
w != window &&
meta_workspace_contains_window (window->screen->active_workspace,
w))
{
windows = g_slist_prepend (windows, w);
++i;
}
tmp = tmp->next;
}
if (n_windows)
*n_windows = i;
return windows;
}
static void
window_get_edges (MetaWindow *w,
int *left,
int *right,
int *top,
int *bottom)
{
int left_edge;
int right_edge;
int top_edge;
int bottom_edge;
MetaRectangle rect;
meta_window_get_outer_rect (w, &rect);
left_edge = rect.x;
right_edge = rect.x + rect.width;
top_edge = rect.y;
bottom_edge = rect.y + rect.height;
if (left)
*left = left_edge;
if (right)
*right = right_edge;
if (top)
*top = top_edge;
if (bottom)
*bottom = bottom_edge;
}
static int
intcmp (const void* a, const void* b)
{
const int *ai = a;
const int *bi = b;
if (*ai < *bi)
return -1;
else if (*ai > *bi)
return 1;
else
return 0;
}
static gboolean
rects_overlap_vertically (const MetaRectangle *a,
const MetaRectangle *b)
{
/* if they don't overlap, then either a is above b
* or b is above a
*/
if ((a->y + a->height) < b->y)
return FALSE;
else if ((b->y + b->height) < a->y)
return FALSE;
else
return TRUE;
}
static gboolean
rects_overlap_horizontally (const MetaRectangle *a,
const MetaRectangle *b)
{
if ((a->x + a->width) < b->x)
return FALSE;
else if ((b->x + b->width) < a->x)
return FALSE;
else
return TRUE;
}
int
meta_window_find_next_vertical_edge (MetaWindow *window,
gboolean right)
{
GSList *windows;
GSList *tmp;
int left_edge, right_edge;
int n_windows;
int *edges;
int i;
int n_edges;
int retval;
MetaRectangle rect;
windows = get_windows_on_same_workspace (window, &n_windows);
i = 0;
n_edges = n_windows * 2 + 4; /* 4 = workspace/screen edges */
edges = g_new (int, n_edges);
/* workspace/screen edges */
edges[i] = window->screen->active_workspace->workarea.x;
++i;
edges[i] =
window->screen->active_workspace->workarea.x +
window->screen->active_workspace->workarea.width;
++i;
edges[i] = 0;
++i;
edges[i] = window->screen->width;
++i;
g_assert (i == 4);
meta_window_get_outer_rect (window, &rect);
/* get window edges */
tmp = windows;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
MetaRectangle w_rect;
meta_window_get_outer_rect (w, &w_rect);
if (rects_overlap_vertically (&rect, &w_rect))
{
window_get_edges (w, &edges[i], &edges[i+1], NULL, NULL);
i += 2;
}
tmp = tmp->next;
}
n_edges = i;
g_slist_free (windows);
/* Sort */
qsort (edges, n_edges, sizeof (int), intcmp);
/* Find next */
meta_window_get_position (window, &retval, NULL);
window_get_edges (window, &left_edge, &right_edge, NULL, NULL);
if (right)
{
i = 0;
while (i < n_edges)
{
if (edges[i] > right_edge)
{
/* This is the one we want, snap right
* edge of window to edges[i]
*/
retval = edges[i];
if (window->frame)
{
retval -= window->frame->rect.width;
retval += window->frame->child_x;
}
else
{
retval -= window->rect.width;
}
break;
}
++i;
}
}
else
{
i = n_edges;
do
{
--i;
if (edges[i] < left_edge)
{
/* This is the one we want */
retval = edges[i];
if (window->frame)
retval += window->frame->child_x;
break;
}
}
while (i > 0);
}
g_free (edges);
return retval;
}
int
meta_window_find_next_horizontal_edge (MetaWindow *window,
gboolean down)
{
GSList *windows;
GSList *tmp;
int top_edge, bottom_edge;
int n_windows;
int *edges;
int i;
int n_edges;
int retval;
MetaRectangle rect;
windows = get_windows_on_same_workspace (window, &n_windows);
i = 0;
n_edges = n_windows * 2 + 4; /* 4 = workspace/screen edges */
edges = g_new (int, n_edges);
/* workspace/screen edges */
edges[i] = window->screen->active_workspace->workarea.y;
++i;
edges[i] =
window->screen->active_workspace->workarea.y +
window->screen->active_workspace->workarea.height;
++i;
edges[i] = 0;
++i;
edges[i] = window->screen->height;
++i;
g_assert (i == 4);
meta_window_get_outer_rect (window, &rect);
/* get window edges */
tmp = windows;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
MetaRectangle w_rect;
meta_window_get_outer_rect (w, &w_rect);
if (rects_overlap_horizontally (&rect, &w_rect))
{
window_get_edges (w, NULL, NULL, &edges[i], &edges[i+1]);
i += 2;
}
tmp = tmp->next;
}
n_edges = i;
g_slist_free (windows);
/* Sort */
qsort (edges, n_edges, sizeof (int), intcmp);
/* Find next */
meta_window_get_position (window, NULL, &retval);
window_get_edges (window, NULL, NULL, &top_edge, &bottom_edge);
if (down)
{
i = 0;
while (i < n_edges)
{
if (edges[i] > bottom_edge)
{
/* This is the one we want, snap right
* edge of window to edges[i]
*/
retval = edges[i];
if (window->frame)
{
retval -= window->frame->rect.height;
retval += window->frame->child_y;
}
else
{
retval -= window->rect.height;
}
break;
}
++i;
}
}
else
{
i = n_edges;
do
{
--i;
if (edges[i] < top_edge)
{
/* This is the one we want */
retval = edges[i];
if (window->frame)
retval += window->frame->child_y;
break;
}
}
while (i > 0);
}
g_free (edges);
return retval;
}

View File

@ -32,6 +32,11 @@ void meta_window_place (MetaWindow *window,
int *new_x,
int *new_y);
int meta_window_find_next_vertical_edge (MetaWindow *window,
gboolean right);
int meta_window_find_next_horizontal_edge (MetaWindow *window,
gboolean down);
#endif

View File

@ -15,7 +15,7 @@ if test -z "$CLIENTS"; then
fi
if test -z "$ONLY_WM"; then
Xnest -ac :1 -scrns $SCREENS -geometry 640x400 -bw 15 &
Xnest -ac :1 -scrns $SCREENS -geometry 640x480 -bw 15 &
usleep 500000
if test $CLIENTS != 0; then

View File

@ -54,6 +54,10 @@ process_ice_messages (GIOChannel *channel,
IceConn connection = (IceConn) client_data;
IceProcessMessagesStatus status;
/* This blocks infinitely sometimes. I don't know what
* to do about it. Checking "condition" just breaks
* session management.
*/
status = IceProcessMessages (connection, NULL, NULL);
if (status == IceProcessMessagesIOError)

View File

@ -1408,12 +1408,16 @@ meta_window_get_position (MetaWindow *window,
{
if (window->frame)
{
if (x)
*x = window->frame->rect.x + window->frame->child_x;
if (y)
*y = window->frame->rect.y + window->frame->child_y;
}
else
{
if (x)
*x = window->rect.x;
if (y)
*y = window->rect.y;
}
}
@ -1489,6 +1493,16 @@ meta_window_get_gravity_position (MetaWindow *window,
*root_y = y;
}
void
meta_window_get_outer_rect (MetaWindow *window,
MetaRectangle *rect)
{
if (window->frame)
*rect = window->frame->rect;
else
*rect = window->rect;
}
void
meta_window_delete (MetaWindow *window,
Time timestamp)

View File

@ -257,6 +257,8 @@ void meta_window_get_position (MetaWindow *window,
void meta_window_get_gravity_position (MetaWindow *window,
int *x,
int *y);
void meta_window_get_outer_rect (MetaWindow *window,
MetaRectangle *rect);
void meta_window_delete (MetaWindow *window,
Time timestamp);
void meta_window_focus (MetaWindow *window,