summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Djärv <jan.h.d@swipnet.se>2006-06-16 12:12:27 +0000
committerJan Djärv <jan.h.d@swipnet.se>2006-06-16 12:12:27 +0000
commitd692a3d5c580f15bc5968a034286922c1a1bf423 (patch)
tree69a256c12c72ecc834a97d2522026b47c5e25884
parentdb600ab1dbf2f0c84e6b82bef80dec3f68326637 (diff)
downloademacs-d692a3d5c580f15bc5968a034286922c1a1bf423.tar.gz
2006-06-16 Francis Litterio <flitterio@gmail.com>
* xterm.c (x_check_expected_move, handle_one_xevent) (x_set_offset, x_check_fullscreen): Extensive changes to make frame positioning deterministic under X. * xterm.h (x_output): Added members left_before_move and top_before_move. Removed members expected_left and expected_top.
-rw-r--r--src/ChangeLog9
-rw-r--r--src/xterm.c139
-rw-r--r--src/xterm.h12
3 files changed, 119 insertions, 41 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 0f16f42b857..536edd3e287 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+2006-06-16 Francis Litterio <flitterio@gmail.com>
+
+ * xterm.c (x_check_expected_move, handle_one_xevent)
+ (x_set_offset, x_check_fullscreen): Extensive changes to make
+ frame positioning deterministic under X.
+
+ * xterm.h (x_output): Added members left_before_move and
+ top_before_move. Removed members expected_left and expected_top.
+
2006-06-16 Kim F. Storm <storm@cua.dk>
* dispextern.h (struct it): Add union to iterator stack to save
diff --git a/src/xterm.c b/src/xterm.c
index 343ca30caa9..dfa5f4f4413 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -354,7 +354,8 @@ static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
Lisp_Object *, Lisp_Object *,
unsigned long *));
static void x_check_fullscreen P_ ((struct frame *));
-static void x_check_expected_move P_ ((struct frame *));
+static void x_check_expected_move P_ ((struct frame *, int, int));
+static void x_sync_with_move P_ ((struct frame *, int, int, int));
static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
int *, struct input_event *));
static SIGTYPE x_connection_closed P_ ((Display *, char *));
@@ -6673,11 +6674,8 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
&& GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
#endif
{
- /* What we have now is the position of Emacs's own window.
- Convert that to the position of the window manager window. */
x_real_positions (f, &f->left_pos, &f->top_pos);
- x_check_expected_move (f);
if (f->want_fullscreen & FULLSCREEN_WAIT)
f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
}
@@ -8223,8 +8221,11 @@ x_set_offset (f, xoff, yoff, change_gravity)
{
int modified_top, modified_left;
- if (change_gravity > 0)
+ if (change_gravity != 0)
{
+ FRAME_X_OUTPUT (f)->left_before_move = f->left_pos;
+ FRAME_X_OUTPUT (f)->top_before_move = f->top_pos;
+
f->top_pos = yoff;
f->left_pos = xoff;
f->size_hint_flags &= ~ (XNegative | YNegative);
@@ -8242,7 +8243,7 @@ x_set_offset (f, xoff, yoff, change_gravity)
modified_left = f->left_pos;
modified_top = f->top_pos;
- if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
+ if (change_gravity != 0 && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
{
/* Some WMs (twm, wmaker at least) has an offset that is smaller
than the WM decorations. So we use the calculated offset instead
@@ -8254,13 +8255,26 @@ x_set_offset (f, xoff, yoff, change_gravity)
XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
modified_left, modified_top);
- if (FRAME_VISIBLE_P (f)
- && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN)
- {
- FRAME_X_OUTPUT (f)->check_expected_move = 1;
- FRAME_X_OUTPUT (f)->expected_top = f->top_pos;
- FRAME_X_OUTPUT (f)->expected_left = f->left_pos;
- }
+ x_sync_with_move (f, f->left_pos, f->top_pos,
+ FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+ ? 1 : 0);
+
+ /* change_gravity is non-zero when this function is called from Lisp to
+ programmatically move a frame. In that case, we call
+ x_check_expected_move to discover if we have a "Type A" or "Type B"
+ window manager, and, for a "Type A" window manager, adjust the position
+ of the frame.
+
+ We call x_check_expected_move if a programmatic move occurred, and
+ either the window manager type (A/B) is unknown or it is Type A but we
+ need to compute the top/left offset adjustment for this frame. */
+
+ if (change_gravity != 0 &&
+ (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+ || (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+ && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+ && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+ x_check_expected_move (f, modified_left, modified_top);
UNBLOCK_INPUT;
}
@@ -8295,37 +8309,96 @@ x_check_fullscreen (f)
}
}
-/* If frame parameters are set after the frame is mapped, we need to move
- the window.
- Some window managers moves the window to the right position, some
- moves the outer window manager window to the specified position.
- Here we check that we are in the right spot. If not, make a second
- move, assuming we are dealing with the second kind of window manager. */
+/* This function is called by x_set_offset to determine whether the window
+ manager interfered with the positioning of the frame. Type A window
+ managers position the surrounding window manager decorations a small
+ amount above and left of the user-supplied position. Type B window
+ managers position the surrounding window manager decorations at the
+ user-specified position. If we detect a Type A window manager, we
+ compensate by moving the window right and down by the proper amount. */
+
static void
-x_check_expected_move (f)
+x_check_expected_move (f, expected_left, expected_top)
struct frame *f;
+ int expected_left;
+ int expected_top;
{
- if (FRAME_X_OUTPUT (f)->check_expected_move)
- {
- int expect_top = FRAME_X_OUTPUT (f)->expected_top;
- int expect_left = FRAME_X_OUTPUT (f)->expected_left;
+ int count = 0, current_left = 0, current_top = 0;
+
+ /* x_real_positions returns the left and top offsets of the outermost
+ window manager window around the frame. */
- if (expect_top != f->top_pos || expect_left != f->left_pos)
+ x_real_positions (f, &current_left, &current_top);
+
+ if (current_left != expected_left || current_top != expected_top)
{
+ /* It's a "Type A" window manager. */
+
+ int adjusted_left;
+ int adjusted_top;
+
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
- FRAME_X_OUTPUT (f)->move_offset_left = expect_left - f->left_pos;
- FRAME_X_OUTPUT (f)->move_offset_top = expect_top - f->top_pos;
+ FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
+ FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
+
+ /* Now fix the mispositioned frame's location. */
- f->left_pos = expect_left;
- f->top_pos = expect_top;
- x_set_offset (f, expect_left, expect_top, 0);
+ adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
+ adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
+
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ adjusted_left, adjusted_top);
+
+ x_sync_with_move (f, expected_left, expected_top, 0);
}
- else if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN)
+ else
+ /* It's a "Type B" window manager. We don't have to adjust the
+ frame's position. */
+
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
+}
+
+
+/* Wait for XGetGeometry to return up-to-date position information for a
+ recently-moved frame. Call this immediately after calling XMoveWindow.
+ If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
+ frame has been moved to, so we use a fuzzy position comparison instead
+ of an exact comparison. */
+
+static void
+x_sync_with_move (f, left, top, fuzzy)
+ struct frame *f;
+ int left, top, fuzzy;
+{
+ int count = 0;
+
+ while (count++ < 50)
+ {
+ int current_left = 0, current_top = 0;
+
+ /* In theory, this call to XSync only needs to happen once, but in
+ practice, it doesn't seem to work, hence the need for the surrounding
+ loop. */
+
+ XSync (FRAME_X_DISPLAY (f), False);
+ x_real_positions (f, &current_left, &current_top);
+
+ if (fuzzy)
+ {
+ /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
+ pixels. */
- /* Just do this once */
- FRAME_X_OUTPUT (f)->check_expected_move = 0;
+ if (abs (current_left - left) <= 10 && abs (current_top - top) <= 40)
+ return;
}
+ else if (current_left == left && current_top == top)
+ return;
+ }
+
+ /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
+ will then return up-to-date position info. */
+
+ wait_reading_process_output (0, 500000, 0, 0, Qnil, NULL, 0);
}
diff --git a/src/xterm.h b/src/xterm.h
index 797c8b30e0f..10a9aaa2961 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -637,18 +637,14 @@ struct x_output
FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */
int focus_state;
- /* The latest move we made to FRAME_OUTER_WINDOW. Saved so we can
- compensate for type A WMs (see wm_type in dpyinfo above). */
- int expected_top;
- int expected_left;
-
/* The offset we need to add to compensate for type A WMs. */
int move_offset_top;
int move_offset_left;
- /* Nonzero if we have made a move and needs to check if the WM placed us
- at the right position. */
- int check_expected_move;
+ /* The frame's left/top offsets before we call XMoveWindow. See
+ x_check_expected_move. */
+ int left_before_move;
+ int top_before_move;
};
#define No_Cursor (None)