diff --git a/src/core/window-private.h b/src/core/window-private.h index 013bad7aa..c3a1c0250 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -682,6 +682,9 @@ void meta_window_frame_size_changed (MetaWindow *window); void meta_window_stack_just_below (MetaWindow *window, MetaWindow *below_this_one); +void meta_window_stack_just_above (MetaWindow *window, + MetaWindow *above_this_one); + void meta_window_set_user_time (MetaWindow *window, guint32 timestamp); diff --git a/src/core/window.c b/src/core/window.c index 1fc483d16..d450a5ce0 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -6728,6 +6728,30 @@ meta_window_stack_just_below (MetaWindow *window, } } +void +meta_window_stack_just_above (MetaWindow *window, + MetaWindow *above_this_one) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (above_this_one != NULL); + + if (window->stack_position < above_this_one->stack_position) + { + meta_topic (META_DEBUG_STACK, + "Setting stack position of window %s to %d (making it above window %s).\n", + window->desc, + above_this_one->stack_position, + above_this_one->desc); + meta_window_set_stack_position (window, above_this_one->stack_position); + } + else + { + meta_topic (META_DEBUG_STACK, + "Window %s was already above window %s.\n", + window->desc, above_this_one->desc); + } +} + /** * meta_window_get_user_time: * @window: a #MetaWindow diff --git a/src/x11/atomnames.h b/src/x11/atomnames.h index e37e8fa59..ff6c6cc2d 100644 --- a/src/x11/atomnames.h +++ b/src/x11/atomnames.h @@ -176,6 +176,7 @@ item(_NET_WM_OPAQUE_REGION) item(_NET_WM_FRAME_DRAWN) item(_NET_WM_FRAME_TIMINGS) item(_NET_WM_WINDOW_OPACITY) +item(_NET_RESTACK_WINDOW) /* eof atomnames.h */ diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index ad5058b8a..bc922c12a 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -2092,6 +2092,32 @@ meta_window_move_resize_request (MetaWindow *window, } } +static void +restack_window (MetaWindow *window, + MetaWindow *sibling, + int direction) +{ + switch (direction) + { + case Above: + if (sibling) + meta_window_stack_just_above (window, sibling); + else + meta_window_raise (window); + break; + case Below: + if (sibling) + meta_window_stack_just_below (window, sibling); + else + meta_window_lower (window); + break; + case TopIf: + case BottomIf: + case Opposite: + break; + } +} + gboolean meta_window_x11_configure_request (MetaWindow *window, XEvent *event) @@ -2125,10 +2151,7 @@ meta_window_x11_configure_request (MetaWindow *window, * the stack looks). * * I'm pretty sure no interesting client uses TopIf, BottomIf, or - * Opposite anyway, so the only possible missing thing is - * Above/Below with a sibling set. For now we just pretend there's - * never a sibling set and always do the full raise/lower instead of - * the raise-just-above/below-sibling. + * Opposite anyway. */ if (event->xconfigurerequest.value_mask & CWStackMode) { @@ -2160,19 +2183,23 @@ meta_window_x11_configure_request (MetaWindow *window, } else { - switch (event->xconfigurerequest.detail) + MetaWindow *sibling = NULL; + /* Handle Above/Below with a sibling set */ + if (event->xconfigurerequest.above != None) { - case Above: - meta_window_raise (window); - break; - case Below: - meta_window_lower (window); - break; - case TopIf: - case BottomIf: - case Opposite: - break; + MetaDisplay *display; + + display = meta_window_get_display (window); + sibling = meta_display_lookup_x_window (display, + event->xconfigurerequest.above); + if (sibling == NULL) + return TRUE; + + meta_topic (META_DEBUG_STACK, + "xconfigure stacking request from window %s sibling %s stackmode %d\n", + window->desc, sibling->desc, event->xconfigurerequest.detail); } + restack_window (window, sibling, event->xconfigurerequest.detail); } } @@ -2245,6 +2272,30 @@ query_pressed_buttons (MetaWindow *window) return button; } +static void +handle_net_restack_window (MetaDisplay *display, + XEvent *event) +{ + MetaWindow *window, *sibling = NULL; + + /* Ignore if this does not come from a pager, see the WM spec + */ + if (event->xclient.data.l[0] != 2) + return; + + window = meta_display_lookup_x_window (display, + event->xclient.window); + + if (window) + { + if (event->xclient.data.l[1]) + sibling = meta_display_lookup_x_window (display, + event->xclient.data.l[1]); + + restack_window (window, sibling, event->xclient.data.l[2]); + } +} + gboolean meta_window_x11_client_message (MetaWindow *window, XEvent *event) @@ -2728,6 +2779,11 @@ meta_window_x11_client_message (MetaWindow *window, meta_window_show_menu (window, META_WINDOW_MENU_WM, x, y); } + else if (event->xclient.message_type == + display->atom__NET_RESTACK_WINDOW) + { + handle_net_restack_window (display, event); + } return FALSE; }