]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkwindow-win32.c
Reimplement _NET_WM_SYNC_REQUEST inside X11 backend
[~andy/gtk] / gdk / win32 / gdkwindow-win32.c
index f2154abf2fe70d79fd4d1424b16e3935ad5b5f7e..039284963c411b54de1ffc687e089b7e2dbac568 100644 (file)
@@ -15,9 +15,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
@@ -29,6 +27,7 @@
 
 #include "config.h"
 #include <stdlib.h>
+#include <windows.h>
 
 #include "gdk.h"
 #include "gdkwindowimpl.h"
@@ -63,6 +62,8 @@ struct _FullscreenInfo
 static void     update_style_bits         (GdkWindow         *window);
 static gboolean _gdk_window_get_functions (GdkWindow         *window,
                                            GdkWMFunction     *functions);
+static HDC     _gdk_win32_impl_acquire_dc (GdkWindowImplWin32 *impl);
+static void    _gdk_win32_impl_release_dc (GdkWindowImplWin32 *impl);
 
 #define WINDOW_IS_TOPLEVEL(window)                \
   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
@@ -135,7 +136,6 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
   impl->hicon_small = NULL;
   impl->hint_flags = 0;
   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
-  impl->extension_events_selected = FALSE;
   impl->transient_owner = NULL;
   impl->transient_children = NULL;
   impl->num_transients = 0;
@@ -490,7 +490,6 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   if (attributes_mask & GDK_WA_VISUAL)
     g_assert (gdk_screen_get_system_visual (screen) == attributes->visual);
 
-  impl->extension_events_selected = FALSE;
   impl->override_redirect = override_redirect;
 
   /* wclass is not any longer set always, but if is ... */
@@ -544,7 +543,7 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
       /* A temp window is not necessarily a top level window */
       dwStyle = (_gdk_root == real_parent ? WS_POPUP : WS_CHILDWINDOW);
       dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
-      dwExStyle |= WS_EX_TOOLWINDOW;
+      dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
       offset_x = _gdk_offset_x;
       offset_y = _gdk_offset_y;
       break;
@@ -870,7 +869,9 @@ adjust_for_gravity_hints (GdkWindow *window,
 
   if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
     {
+#ifdef G_ENABLE_DEBUG
       gint orig_x = *x, orig_y = *y;
+#endif
 
       switch (impl->hints.win_gravity)
        {
@@ -933,7 +934,6 @@ show_window_internal (GdkWindow *window,
                      gboolean   deiconify)
 {
   GdkWindowImplWin32 *window_impl;
-  HWND old_active_window;
   gboolean focus_on_map = FALSE;
   DWORD exstyle;
 
@@ -1065,6 +1065,57 @@ show_window_internal (GdkWindow *window,
                               SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
     }
 
+  if (!already_mapped &&
+      GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL &&
+      !window_impl->override_redirect)
+    {
+      /* Ensure new windows are fully onscreen */
+      RECT window_rect;
+      HMONITOR monitor;
+      MONITORINFO mi;
+      int x, y;
+
+      GetWindowRect (GDK_WINDOW_HWND (window), &window_rect);
+
+      monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
+      mi.cbSize = sizeof (mi);
+      if (monitor && GetMonitorInfo (monitor, &mi))
+       {
+         x = window_rect.left;
+         y = window_rect.top;
+
+         if (window_rect.right > mi.rcWork.right)
+           {
+             window_rect.left -= (window_rect.right - mi.rcWork.right);
+             window_rect.right -= (window_rect.right - mi.rcWork.right);
+           }
+
+         if (window_rect.bottom > mi.rcWork.bottom)
+           {
+             window_rect.top -= (window_rect.bottom - mi.rcWork.bottom);
+             window_rect.bottom -= (window_rect.bottom - mi.rcWork.bottom);
+           }
+
+         if (window_rect.left < mi.rcWork.left)
+           {
+             window_rect.right += (mi.rcWork.left - window_rect.left);
+             window_rect.left += (mi.rcWork.left - window_rect.left);
+           }
+
+         if (window_rect.top < mi.rcWork.top)
+           {
+             window_rect.bottom += (mi.rcWork.top - window_rect.top);
+             window_rect.top += (mi.rcWork.top - window_rect.top);
+           }
+
+         if (x != window_rect.left || y != window_rect.top)
+           API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
+                                    window_rect.left, window_rect.top, 0, 0,
+                                    SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
+       }
+    }
+
+
   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
     {
       gdk_window_fullscreen (window);
@@ -1090,10 +1141,11 @@ show_window_internal (GdkWindow *window,
     }
 
   /* Sync STATE_ABOVE to TOPMOST */
-  if (((window->state & GDK_WINDOW_STATE_ABOVE) &&
-       !(exstyle & WS_EX_TOPMOST)) ||
-      (!(window->state & GDK_WINDOW_STATE_ABOVE) &&
-       (exstyle & WS_EX_TOPMOST)))
+  if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP &&
+      (((window->state & GDK_WINDOW_STATE_ABOVE) &&
+       !(exstyle & WS_EX_TOPMOST)) ||
+       (!(window->state & GDK_WINDOW_STATE_ABOVE) &&
+       (exstyle & WS_EX_TOPMOST))))
     {
       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
                               (window->state & GDK_WINDOW_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
@@ -1448,7 +1500,11 @@ gdk_win32_window_raise (GdkWindow *window)
                                 0, 0, 0, 0,
                                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
       else if (window->accept_focus)
-        API_CALL (BringWindowToTop, (GDK_WINDOW_HWND (window)));
+        /* Do not wrap this in an API_CALL macro as SetForegroundWindow might
+         * fail when for example dragging a window belonging to a different
+         * application at the time of a gtk_window_present() call due to focus
+         * stealing prevention. */
+        SetForegroundWindow (GDK_WINDOW_HWND (window));
       else
         API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
                                 0, 0, 0, 0,
@@ -1478,7 +1534,7 @@ gdk_win32_window_set_urgency_hint (GdkWindow *window,
                             gboolean   urgent)
 {
   FLASHWINFO flashwinfo;
-  typedef BOOL (*PFN_FlashWindowEx) (FLASHWINFO*);
+  typedef BOOL (WINAPI *PFN_FlashWindowEx) (FLASHWINFO*);
   PFN_FlashWindowEx flashWindowEx = NULL;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
@@ -2398,9 +2454,10 @@ update_style_bits (GdkWindow *window)
   new_style = old_style;
   new_exstyle = old_exstyle;
 
-  if (window->window_type == GDK_WINDOW_TEMP ||
-      impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
-    new_exstyle |= WS_EX_TOOLWINDOW;
+  if (window->window_type == GDK_WINDOW_TEMP)
+    new_exstyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+  else if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
+    new_exstyle |= WS_EX_TOOLWINDOW ;
   else
     new_exstyle &= ~WS_EX_TOOLWINDOW;
 
@@ -3191,24 +3248,12 @@ gdk_win32_window_lookup_for_display (GdkDisplay *display,
   return (GdkWindow*) gdk_win32_handle_table_lookup (anid);
 }
 
-static void
-gdk_win32_window_enable_synchronized_configure (GdkWindow *window)
-{
-  /* nothing - no window manager to cooperate with */
-}
-
-static void
-gdk_win32_window_configure_finished (GdkWindow *window)
-{
-  /* nothing - no window manager to cooperate with */
-}
-
 static void
 gdk_win32_window_set_opacity (GdkWindow *window,
                        gdouble    opacity)
 {
   LONG exstyle;
-  typedef BOOL (*PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+  typedef BOOL (WINAPI *PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
   PFN_SetLayeredWindowAttributes setLayeredWindowAttributes = NULL;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
@@ -3285,20 +3330,68 @@ _gdk_win32_window_translate (GdkWindow *window,
                              gint       dx,
                              gint       dy)
 {
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
   GdkRectangle extents;
   RECT rect;
+  HRGN hrgn, area_hrgn;
+  HDC hdc;
+  int ret;
+
+  /* Note: This is the destination area, not the source, and
+     it has been moved by dx, dy from the source area */
+  area_hrgn = cairo_region_to_hrgn (area, 0, 0);
+
+  /* First we copy any outstanding invalid areas in the 
+     source area to the new position in the destination area */
+  hrgn = CreateRectRgn (0, 0, 0, 0);
+  ret = GetUpdateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE);
+  if (ret == ERROR)
+    WIN32_API_FAILED ("GetUpdateRgn");
+  else if (ret != NULLREGION)
+    {
+      /* Convert the source invalid region as it would be copied */
+      OffsetRgn (hrgn, dx, dy);
+      /* Keep what intersects the copy destination area */
+      ret = CombineRgn (hrgn, hrgn, area_hrgn, RGN_AND);
+      /* And invalidate it */
+      if (ret == ERROR)
+        WIN32_API_FAILED ("CombineRgn");
+      else if (ret != NULLREGION)
+       API_CALL (InvalidateRgn, (GDK_WINDOW_HWND (window), hrgn, TRUE));
+    }
+
+  /* Then we copy the bits, invalidating whatever is copied from
+     otherwise invisible areas */
+
+  hdc = _gdk_win32_impl_acquire_dc (impl);
+
+  /* Clip hdc to target region */
+  API_CALL (SelectClipRgn, (hdc, area_hrgn));
 
   cairo_region_get_extents (area, &extents);
-  rect.left = extents.x - dx;
-  rect.top = extents.y - dy;
-  rect.right = rect.left + extents.width;
-  rect.bottom = rect.top + extents.height;
 
-  API_CALL (ScrollWindowEx, (GDK_WINDOW_HWND (window), 
-                            dx, dy, &rect, 
-                            NULL, NULL, NULL, 
-                            SW_INVALIDATE));
+  rect.left = MIN (extents.x, extents.x - dx);
+  rect.top = MIN (extents.y, extents.y - dy);
+  rect.right = MAX (extents.x + extents.width, extents.x - dx  + extents.width);
+  rect.bottom = MAX (extents.y + extents.height, extents.y - dy  + extents.height);
+
+  SetRectRgn (hrgn, 0, 0, 0, 0);
+
+  if (!ScrollDC (hdc, dx, dy, &rect, NULL, hrgn, NULL))
+    WIN32_GDI_FAILED ("ScrollDC");
+  else if (!InvalidateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE))
+    WIN32_GDI_FAILED ("InvalidateRgn");
+
+  /* Unset hdc clip region */
+  API_CALL (SelectClipRgn, (hdc, NULL));
+
+  _gdk_win32_impl_release_dc (impl);
+
+  if (!DeleteObject (hrgn))
+    WIN32_GDI_FAILED ("DeleteObject");
 
+  if (!DeleteObject (area_hrgn))
+    WIN32_GDI_FAILED ("DeleteObject");
 }
 
 static void
@@ -3513,8 +3606,6 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
 
   impl_class->begin_resize_drag = gdk_win32_window_begin_resize_drag;
   impl_class->begin_move_drag = gdk_win32_window_begin_move_drag;
-  impl_class->enable_synchronized_configure = gdk_win32_window_enable_synchronized_configure;
-  impl_class->configure_finished = gdk_win32_window_configure_finished;
   impl_class->set_opacity = gdk_win32_window_set_opacity;
   //impl_class->set_composited = gdk_win32_window_set_composited;
   impl_class->destroy_notify = gdk_win32_window_destroy_notify;