From 99be3d68b64059caada739a373e5e01844c776e0 Mon Sep 17 00:00:00 2001
From: Jeremy Huddleston <jeremyhu@freedesktop.org>
Date: Wed, 8 Oct 2008 18:39:41 -0700
Subject: [PATCH 01/16] XQuartz: Some motion made towards supporting fullscreen.

---
 hw/xquartz/X11Application.h     |    1 +
 hw/xquartz/X11Application.m     |   10 +--
 hw/xquartz/X11Controller.m      |    6 +--
 hw/xquartz/darwinEvents.c       |   11 +---
 hw/xquartz/quartz.c             |  118 +++++++++++++++++++++++++++++---------
 hw/xquartz/quartz.h             |    3 +
 hw/xquartz/quartzCommon.h       |    1 +
 miext/rootless/rootlessCommon.h |   12 ++++-
 miext/rootless/rootlessScreen.c |   43 ++++++++++++++
 miext/rootless/rootlessWindow.c |  102 +++++++++++++++++++++++++++++++++
 10 files changed, 257 insertions(+), 50 deletions(-)

diff --git hw/xquartz/X11Application.h hw/xquartz/X11Application.h
index 0caaba8..4335abc 100644
--- hw/xquartz/X11Application.h
+++ hw/xquartz/X11Application.h
@@ -81,6 +81,7 @@ extern int quartzHasRoot, quartzEnableRootless;
 #define PREFS_FAKEBUTTONS           "enable_fake_buttons"
 #define PREFS_SYSBEEP               "enable_system_beep"
 #define PREFS_KEYEQUIVS             "enable_key_equivalents"
+#define PREFS_FULLSCREEN_HOTKEYS    "fullscreen_hotkeys"
 #define PREFS_SYNC_KEYMAP           "sync_keymap"
 #define PREFS_DEPTH                 "depth"
 #define PREFS_NO_AUTH               "no_auth"
diff --git hw/xquartz/X11Application.m hw/xquartz/X11Application.m
index fc2a535..982df39 100644
--- hw/xquartz/X11Application.m
+++ hw/xquartz/X11Application.m
@@ -624,16 +624,12 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) {
 	
     quartzUseSysBeep = [self prefs_get_boolean:@PREFS_SYSBEEP
                         default:quartzUseSysBeep];
-
-    // TODO: Add fullscreen support
-    //quartzEnableRootless = [self prefs_get_boolean:@PREFS_ROOTLESS
-    //                    default:quartzEnableRootless];
-#ifdef DARWIN_DDX_MISSING
+#if 0
+    quartzEnableRootless = [self prefs_get_boolean:@PREFS_ROOTLESS
+                        default:quartzEnableRootless];
     quartzFullscreenDisableHotkeys = ![self prefs_get_boolean:
 					      @PREFS_FULLSCREEN_HOTKEYS default:
 					      !quartzFullscreenDisableHotkeys];
-    quartzXpluginOptions = [self prefs_get_integer:@PREFS_XP_OPTIONS
-                            default:quartzXpluginOptions];
 #endif
     darwinFakeButtons = [self prefs_get_boolean:@PREFS_FAKEBUTTONS
                          default:darwinFakeButtons];
diff --git hw/xquartz/X11Controller.m hw/xquartz/X11Controller.m
index 2482c05..8513386 100644
--- hw/xquartz/X11Controller.m
+++ hw/xquartz/X11Controller.m
@@ -595,10 +595,8 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
 - (IBAction) enable_fullscreen_changed:sender
 {
   int value = ![enable_fullscreen intValue];
-	
-#ifdef DARWIN_DDX_MISSING
+
   DarwinSendDDXEvent(kXquartzSetRootless, 1, value);
-#endif
 	
   [NSApp prefs_set_boolean:@PREFS_ROOTLESS value:value];
   [NSApp prefs_synchronize];
@@ -606,9 +604,7 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
 
 - (IBAction) toggle_fullscreen:sender
 {
-#ifdef DARWIN_DDX_MISSING
   DarwinSendDDXEvent(kXquartzToggleFullscreen, 0);
-#endif
 }
 
 - (void) set_can_quit:(OSX_BOOL)state
diff --git hw/xquartz/darwinEvents.c hw/xquartz/darwinEvents.c
index 9819618..9acc0cc 100644
--- hw/xquartz/darwinEvents.c
+++ hw/xquartz/darwinEvents.c
@@ -232,27 +232,20 @@ static void DarwinEventHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, in
                 
             case kXquartzToggleFullscreen:
                 DEBUG_LOG("kXquartzToggleFullscreen\n");
-#ifdef DARWIN_DDX_MISSING
                 if (quartzEnableRootless) 
                     QuartzSetFullscreen(!quartzHasRoot);
                 else if (quartzHasRoot)
                     QuartzHide();
                 else
-                    QuartzShow();
-#else
-                //      ErrorF("kXquartzToggleFullscreen not implemented\n");               
-#endif
+                    QuartzShow(xe[i].u.keyButtonPointer.rootX,
+                               xe[i].u.keyButtonPointer.rootY);
                 break;
                 
             case kXquartzSetRootless:
                 DEBUG_LOG("kXquartzSetRootless\n");
-#ifdef DARWIN_DDX_MISSING
                 QuartzSetRootless(xe[i].u.clientMessage.u.l.longs0);
                 if (!quartzEnableRootless && !quartzHasRoot)
                     QuartzHide();
-#else
-                //      ErrorF("kXquartzSetRootless not implemented\n");                    
-#endif
                 break;
                 
             case kXquartzSetRootClip:
diff --git hw/xquartz/quartz.c hw/xquartz/quartz.c
index 8c8b8f8..8032705 100644
--- hw/xquartz/quartz.c
+++ hw/xquartz/quartz.c
@@ -61,6 +61,9 @@
 #include <fcntl.h>
 #include <IOKit/pwr_mgt/IOPMLib.h>
 
+#include <rootlessCommon.h>
+#include <Xplugin.h>
+
 #define FAKE_RANDR 1
 
 // Shared global variables for Quartz modes
@@ -75,6 +78,7 @@ int                     quartzScreenIndex = 0;
 int                     aquaMenuBarHeight = 0;
 QuartzModeProcsPtr      quartzProcs = NULL;
 const char             *quartzOpenGLBundle = NULL;
+int                     quartzFullscreenDisableHotkeys = TRUE;
 
 #if defined(RANDR) && !defined(FAKE_RANDR)
 Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) {
@@ -236,33 +240,27 @@ RREditConnectionInfo (ScreenPtr pScreen)
 }
 #endif
 
-/*
- * QuartzDisplayChangeHandler
- *  Adjust for screen arrangement changes.
- */
-void QuartzDisplayChangedHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, int nevents)
-{
+static void QuartzUpdateScreens(void) {
     ScreenPtr pScreen;
     WindowPtr pRoot;
     int x, y, width, height, sx, sy;
     xEvent e;
-
-    DEBUG_LOG("QuartzDisplayChangedHandler(): noPseudoramiXExtension=%d, screenInfo.numScreens=%d\n", noPseudoramiXExtension, screenInfo.numScreens);
+    
     if (noPseudoramiXExtension || screenInfo.numScreens != 1)
     {
         /* FIXME: if not using Xinerama, we have multiple screens, and
-           to do this properly may need to add or remove screens. Which
-           isn't possible. So don't do anything. Another reason why
-           we default to running with Xinerama. */
-
+         to do this properly may need to add or remove screens. Which
+         isn't possible. So don't do anything. Another reason why
+         we default to running with Xinerama. */
+        
         return;
     }
-
+    
     pScreen = screenInfo.screens[0];
-
+    
     PseudoramiXResetScreens();
     quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height);
-
+    
     dixScreenOrigins[pScreen->myNum].x = x;
     dixScreenOrigins[pScreen->myNum].y = y;
     pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width);
@@ -274,21 +272,20 @@ void QuartzDisplayChangedHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev,
     if(!QuartzRandRInit(pScreen))
         FatalError("Failed to init RandR extension.\n");
 #endif
-
+    
     DarwinAdjustScreenOrigins(&screenInfo);
     quartzProcs->UpdateScreen(pScreen);
-
+    
     sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
     sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
-
+    
     /* Adjust the root window. */
     pRoot = WindowTable[pScreen->myNum];
     AppleWMSetScreenOrigin(pRoot);
     pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL);
     miPaintWindow(pRoot, &pRoot->borderClip,  PW_BACKGROUND);
-//    QuartzIgnoreNextWarpCursor();
     DefineInitialRootWindow(pRoot);
-
+    
     /* Send an event for the root reconfigure */
     e.u.u.type = ConfigureNotify;
     e.u.configureNotify.window = pRoot->drawable.id;
@@ -300,12 +297,71 @@ void QuartzDisplayChangedHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev,
     e.u.configureNotify.borderWidth = wBorderWidth(pRoot);
     e.u.configureNotify.override = pRoot->overrideRedirect;
     DeliverEvents(pRoot, &e, 1, NullWindow);
-
+    
 #ifdef FAKE_RANDR
     RREditConnectionInfo(pScreen);
-#endif
+#endif    
 }
 
+/*
+ * QuartzDisplayChangeHandler
+ *  Adjust for screen arrangement changes.
+ */
+void QuartzDisplayChangedHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, int nevents) {
+    QuartzUpdateScreens();
+}
+
+void QuartzSetFullscreen(Bool state) {
+    if(quartzHasRoot == state)
+        return;
+    
+    quartzHasRoot = state;
+    
+    xp_disable_update ();
+    
+    if (!quartzHasRoot && !quartzEnableRootless)
+        RootlessHideAllWindows();
+    
+    RootlessUpdateRooted(quartzHasRoot);
+    
+    if (quartzHasRoot && !quartzEnableRootless)
+        RootlessShowAllWindows ();
+    
+    /* Only update screen info when something is visible. Avoids the wm
+     * moving the windows out from under the menubar when it shouldn't
+     */
+    if (quartzHasRoot || quartzEnableRootless)
+        QuartzUpdateScreens();
+    
+    /* Somehow the menubar manages to interfere with our event stream
+     * in fullscreen mode, even though it's not visible. 
+     */
+    
+    X11ApplicationShowHideMenubar(!quartzHasRoot);
+    
+    xp_reenable_update ();
+    
+    if (quartzFullscreenDisableHotkeys)
+        xp_disable_hot_keys(quartzHasRoot);
+}
+
+void QuartzSetRootless(Bool state) {
+    if(quartzEnableRootless == state)
+        return;
+    
+    quartzEnableRootless = state;
+    
+    if (!quartzEnableRootless && !quartzHasRoot) {
+        xp_disable_update();
+        RootlessHideAllWindows();
+        xp_reenable_update();
+    } else if (quartzEnableRootless && !quartzHasRoot) {
+        xp_disable_update();
+        RootlessShowAllWindows();
+        QuartzUpdateScreens();
+        xp_reenable_update();
+    }
+}
 
 /*
  * QuartzShow
@@ -319,14 +375,18 @@ void QuartzShow(
 {
     int i;
 
-    if (!quartzServerVisible) {
-        quartzServerVisible = TRUE;
-        for (i = 0; i < screenInfo.numScreens; i++) {
-            if (screenInfo.screens[i]) {
-                quartzProcs->ResumeScreen(screenInfo.screens[i], x, y);
-            }
+    if (quartzServerVisible)
+        return;
+    
+    quartzServerVisible = TRUE;
+    for (i = 0; i < screenInfo.numScreens; i++) {
+        if (screenInfo.screens[i]) {
+            quartzProcs->ResumeScreen(screenInfo.screens[i], x, y);
         }
     }
+    
+    if (!quartzEnableRootless)
+        QuartzSetFullscreen(TRUE);
 }
 
 
@@ -347,6 +407,8 @@ void QuartzHide(void)
             }
         }
     }
+    
+    QuartzSetFullscreen(FALSE);
     quartzServerVisible = FALSE;
 }
 
diff --git hw/xquartz/quartz.h hw/xquartz/quartz.h
index 1b6d71f..8b04b79 100644
--- hw/xquartz/quartz.h
+++ hw/xquartz/quartz.h
@@ -137,4 +137,7 @@ void QuartzShow(int x, int y); // (x, y) = cursor loc
 void QuartzHide(void);
 void QuartzSetRootClip(BOOL enable);
 void QuartzSpaceChanged(uint32_t space_id);
+
+void QuartzSetFullscreen(Bool state);
+void QuartzSetRootless(Bool state);
 #endif
diff --git hw/xquartz/quartzCommon.h hw/xquartz/quartzCommon.h
index 99bac19..5371d29 100644
--- hw/xquartz/quartzCommon.h
+++ hw/xquartz/quartzCommon.h
@@ -59,6 +59,7 @@ extern int              quartzUseSysBeep;
 extern int              focusOnNewWindow;
 extern int              quartzUseAGL;
 extern int              quartzEnableKeyEquivalents;
+extern int              quartzFullscreenDisableHotkeys;
 
 // Other shared data
 extern int              quartzServerVisible;
diff --git miext/rootless/rootlessCommon.h miext/rootless/rootlessCommon.h
index ce9d853..7ba4615 100644
--- miext/rootless/rootlessCommon.h
+++ miext/rootless/rootlessCommon.h
@@ -274,7 +274,8 @@ Bool RootlessResolveColormap (ScreenPtr pScreen, int first_color,
 void RootlessFlushWindowColormap (WindowPtr pWin);
 void RootlessFlushScreenColormaps (ScreenPtr pScreen);
 
-RootlessColormapCallback(void *data, int first_color, int n_colors, uint32_t *colors);
+// xp_error
+int RootlessColormapCallback(void *data, int first_color, int n_colors, uint32_t *colors);
 
 // Move a window to its proper location on the screen.
 void RootlessRepositionWindow(WindowPtr pWin);
@@ -282,4 +283,13 @@ void RootlessRepositionWindow(WindowPtr pWin);
 // Move the window to it's correct place in the physical stacking order.
 void RootlessReorderWindow(WindowPtr pWin);
 
+void RootlessScreenExpose (ScreenPtr pScreen);
+void RootlessHideAllWindows (void);
+void RootlessShowAllWindows (void);
+void RootlessUpdateRooted (Bool state);
+
+void RootlessEnableRoot (ScreenPtr pScreen);
+void RootlessDisableRoot (ScreenPtr pScreen);
+
+
 #endif /* _ROOTLESSCOMMON_H */
diff --git miext/rootless/rootlessScreen.c miext/rootless/rootlessScreen.c
index 503d57c..be881cf 100644
--- miext/rootless/rootlessScreen.c
+++ miext/rootless/rootlessScreen.c
@@ -471,6 +471,34 @@ RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
     return result;
 }
 
+expose_1 (WindowPtr pWin)
+{
+    WindowPtr pChild;
+    
+    if (!pWin->realized)
+        return;
+    
+    (*pWin->drawable.pScreen->PaintWindowBackground) (pWin, &pWin->borderClip,
+                                                      PW_BACKGROUND);
+    
+    /* FIXME: comments in windowstr.h indicate that borderClip doesn't
+     include subwindow visibility. But I'm not so sure.. so we may
+     be exposing too much.. */
+    
+    miSendExposures (pWin, &pWin->borderClip,
+                     pWin->drawable.x, pWin->drawable.y);
+    
+    for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
+        expose_1 (pChild);
+}
+
+void
+RootlessScreenExpose (ScreenPtr pScreen)
+{
+    expose_1 (WindowTable[pScreen->myNum]);
+}
+
+
 ColormapPtr
 RootlessGetColormap (ScreenPtr pScreen)
 {
@@ -739,3 +767,18 @@ Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
 
     return TRUE;
 }
+
+void RootlessUpdateRooted (Bool state) {
+    int i;
+    
+    if (!state)
+    {
+        for (i = 0; i < screenInfo.numScreens; i++)
+            RootlessDisableRoot (screenInfo.screens[i]);
+    }
+    else
+    {
+        for (i = 0; i < screenInfo.numScreens; i++)
+            RootlessEnableRoot (screenInfo.screens[i]);
+    }
+}
diff --git miext/rootless/rootlessWindow.c miext/rootless/rootlessWindow.c
index 4af0d99..5bba1d2 100644
--- miext/rootless/rootlessWindow.c
+++ miext/rootless/rootlessWindow.c
@@ -1680,3 +1680,105 @@ RootlessOrderAllWindows (void)
     }
     RL_DEBUG_MSG("RootlessOrderAllWindows() done");
 }
+
+void
+RootlessEnableRoot (ScreenPtr pScreen)
+{
+    WindowPtr pRoot;
+    pRoot = WindowTable[pScreen->myNum];
+    
+    RootlessEnsureFrame (pRoot);
+    (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
+    RootlessReorderWindow (pRoot);
+}
+
+void
+RootlessDisableRoot (ScreenPtr pScreen)
+{
+    WindowPtr pRoot;
+    RootlessWindowRec *winRec;
+    
+    pRoot = WindowTable[pScreen->myNum];
+    winRec = WINREC (pRoot);
+    
+    if (winRec != NULL)
+    {
+        RootlessDestroyFrame (pRoot, winRec);
+        DeleteProperty (pRoot, xa_native_window_id ());
+    }
+}
+
+void
+RootlessHideAllWindows (void)
+{
+    int i;
+    ScreenPtr pScreen;
+    WindowPtr pWin;
+    RootlessWindowRec *winRec;
+    xp_window_changes wc;
+    
+    if (windows_hidden)
+        return;
+    
+    windows_hidden = TRUE;
+    
+    for (i = 0; i < screenInfo.numScreens; i++)
+    {
+        pScreen = screenInfo.screens[i];
+        pWin = WindowTable[i];
+        if (pScreen == NULL || pWin == NULL)
+            continue;
+        
+        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
+        {
+            if (!pWin->realized)
+                continue;
+            
+            RootlessStopDrawing (pWin, FALSE);
+            
+            winRec = WINREC (pWin);
+            if (winRec != NULL)
+            {
+                wc.stack_mode = XP_UNMAPPED;
+                wc.sibling = 0;
+                configure_window ((xp_window_id)winRec->wid, XP_STACKING, &wc);
+            }
+        }
+    }
+}
+
+void
+RootlessShowAllWindows (void)
+{
+    int i;
+    ScreenPtr pScreen;
+    WindowPtr pWin;
+    RootlessWindowRec *winRec;
+    
+    if (!windows_hidden)
+        return;
+    
+    windows_hidden = FALSE;
+    
+    for (i = 0; i < screenInfo.numScreens; i++)
+    {
+        pScreen = screenInfo.screens[i];
+        pWin = WindowTable[i];
+        if (pScreen == NULL || pWin == NULL)
+            continue;
+        
+        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
+        {
+            if (!pWin->realized)
+                continue;
+            
+            winRec = RootlessEnsureFrame (pWin);
+            if (winRec == NULL)
+                continue;
+            
+            RootlessReorderWindow (pWin);
+        }
+        
+        RootlessScreenExpose (pScreen);
+    }
+}
-- 
1.6.1

