Do reinitialization of screen info at the screen manager level, so we get it for the xinerama codepath too. (Bug 403706) r+sr=roc

This commit is contained in:
L. David Baron 2008-07-13 20:20:30 -07:00
parent e8500a84b7
commit 20f6889807
4 changed files with 128 additions and 100 deletions

View File

@ -42,36 +42,8 @@
#include <gtk/gtk.h>
#include <X11/Xatom.h>
static GdkFilterReturn
root_window_event_filter(GdkXEvent *aGdkXEvent, GdkEvent *aGdkEvent,
gpointer aClosure)
{
XEvent *xevent = static_cast<XEvent*>(aGdkXEvent);
nsScreenGtk *ourScreen = static_cast<nsScreenGtk*>(aClosure);
// See comments in nsScreenGtk::Init below.
switch (xevent->type) {
case ConfigureNotify:
ourScreen->ReInit();
break;
case PropertyNotify:
{
XPropertyEvent *propertyEvent = &xevent->xproperty;
if (propertyEvent->atom == ourScreen->NetWorkareaAtom()) {
ourScreen->ReInit();
}
}
break;
default:
break;
}
return GDK_FILTER_CONTINUE;
}
nsScreenGtk :: nsScreenGtk ( )
: mRootWindow(nsnull),
mScreenNum(0),
: mScreenNum(0),
mRect(0, 0, 0, 0),
mAvailRect(0, 0, 0, 0)
{
@ -80,11 +52,6 @@ nsScreenGtk :: nsScreenGtk ( )
nsScreenGtk :: ~nsScreenGtk()
{
if (mRootWindow) {
gdk_window_remove_filter(mRootWindow, root_window_event_filter, this);
g_object_unref(mRootWindow);
mRootWindow = nsnull;
}
}
@ -138,7 +105,7 @@ nsScreenGtk :: GetColorDepth(PRInt32 *aColorDepth)
void
nsScreenGtk :: Init (PRBool aReInit)
nsScreenGtk :: Init (GdkWindow *aRootWindow)
{
// We listen for configure events on the root window to pick up
// changes to this rect. We could listen for "size_changed" signals
@ -154,25 +121,6 @@ nsScreenGtk :: Init (PRBool aReInit)
// could have a non-rectangular shape), but should
// lead to greater accuracy.
if (!aReInit) {
#if GTK_CHECK_VERSION(2,2,0)
mRootWindow = gdk_get_default_root_window();
#else
mRootWindow = GDK_ROOT_PARENT();
#endif // GTK_CHECK_VERSION(2,2,0)
g_object_ref(mRootWindow);
// GDK_STRUCTURE_MASK ==> StructureNotifyMask, for ConfigureNotify
// GDK_PROPERTY_CHANGE_MASK ==> PropertyChangeMask, for PropertyNotify
gdk_window_set_events(mRootWindow,
GdkEventMask(gdk_window_get_events(mRootWindow) |
GDK_STRUCTURE_MASK |
GDK_PROPERTY_CHANGE_MASK));
gdk_window_add_filter(mRootWindow, root_window_event_filter, this);
mNetWorkareaAtom =
XInternAtom(GDK_WINDOW_XDISPLAY(mRootWindow), "_NET_WORKAREA", False);
}
long *workareas;
GdkAtom type_returned;
int format_returned;
@ -187,7 +135,7 @@ nsScreenGtk :: Init (PRBool aReInit)
gdk_error_trap_push();
// gdk_property_get uses (length + 3) / 4, hence G_MAXLONG - 3 here.
if (!gdk_property_get(mRootWindow,
if (!gdk_property_get(aRootWindow,
gdk_atom_intern ("_NET_WORKAREA", FALSE),
cardinal_atom,
0, G_MAXLONG - 3, FALSE,

View File

@ -63,16 +63,11 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSISCREEN
void Init(PRBool aReInit = PR_FALSE);
void ReInit() { Init(PR_TRUE); }
void Init(GdkWindow *aRootWindow);
void Init(XineramaScreenInfo *aScreenInfo);
Atom NetWorkareaAtom() { return mNetWorkareaAtom; }
private:
GdkWindow *mRootWindow;
PRUint32 mScreenNum;
Atom mNetWorkareaAtom;
nsRect mRect; // in pixels, not twips
nsRect mAvailRect; // in pixels, not twips
};

View File

@ -44,6 +44,7 @@
#include "nsAutoPtr.h"
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#define SCREEN_MANAGER_LIBRARY_LOAD_FAILED ((PRLibrary*)1)
@ -51,8 +52,36 @@
typedef Bool (*_XnrmIsActive_fn)(Display *dpy);
typedef XineramaScreenInfo* (*_XnrmQueryScreens_fn)(Display *dpy, int *number);
static GdkFilterReturn
root_window_event_filter(GdkXEvent *aGdkXEvent, GdkEvent *aGdkEvent,
gpointer aClosure)
{
XEvent *xevent = static_cast<XEvent*>(aGdkXEvent);
nsScreenManagerGtk *manager = static_cast<nsScreenManagerGtk*>(aClosure);
// See comments in nsScreenGtk::Init below.
switch (xevent->type) {
case ConfigureNotify:
manager->Init();
break;
case PropertyNotify:
{
XPropertyEvent *propertyEvent = &xevent->xproperty;
if (propertyEvent->atom == manager->NetWorkareaAtom()) {
manager->Init();
}
}
break;
default:
break;
}
return GDK_FILTER_CONTINUE;
}
nsScreenManagerGtk :: nsScreenManagerGtk ( )
: mXineramalib(nsnull)
, mRootWindow(nsnull)
{
// nothing else to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
@ -62,6 +91,12 @@ nsScreenManagerGtk :: nsScreenManagerGtk ( )
nsScreenManagerGtk :: ~nsScreenManagerGtk()
{
if (mRootWindow) {
gdk_window_remove_filter(mRootWindow, root_window_event_filter, this);
g_object_unref(mRootWindow);
mRootWindow = nsnull;
}
if (mXineramalib && mXineramalib != SCREEN_MANAGER_LIBRARY_LOAD_FAILED) {
PR_UnloadLibrary(mXineramalib);
}
@ -74,63 +109,103 @@ NS_IMPL_ISUPPORTS1(nsScreenManagerGtk, nsIScreenManager)
// this function will make sure that everything has been initialized.
nsresult
nsScreenManagerGtk :: EnsureInit(void)
nsScreenManagerGtk :: EnsureInit()
{
if (mCachedScreenArray.Count() == 0) {
XineramaScreenInfo *screenInfo = NULL;
int numScreens;
if (mCachedScreenArray.Count() > 0)
return NS_OK;
#if GTK_CHECK_VERSION(2,2,0)
mRootWindow = gdk_get_default_root_window();
#else
mRootWindow = GDK_ROOT_PARENT();
#endif // GTK_CHECK_VERSION(2,2,0)
g_object_ref(mRootWindow);
// GDK_STRUCTURE_MASK ==> StructureNotifyMask, for ConfigureNotify
// GDK_PROPERTY_CHANGE_MASK ==> PropertyChangeMask, for PropertyNotify
gdk_window_set_events(mRootWindow,
GdkEventMask(gdk_window_get_events(mRootWindow) |
GDK_STRUCTURE_MASK |
GDK_PROPERTY_CHANGE_MASK));
gdk_window_add_filter(mRootWindow, root_window_event_filter, this);
mNetWorkareaAtom =
XInternAtom(GDK_WINDOW_XDISPLAY(mRootWindow), "_NET_WORKAREA", False);
return Init();
}
nsresult
nsScreenManagerGtk :: Init()
{
XineramaScreenInfo *screenInfo = NULL;
int numScreens;
if (!mXineramalib) {
mXineramalib = PR_LoadLibrary("libXinerama.so.1");
if (!mXineramalib) {
mXineramalib = PR_LoadLibrary("libXinerama.so.1");
if (!mXineramalib) {
mXineramalib = SCREEN_MANAGER_LIBRARY_LOAD_FAILED;
}
mXineramalib = SCREEN_MANAGER_LIBRARY_LOAD_FAILED;
}
if (mXineramalib && mXineramalib != SCREEN_MANAGER_LIBRARY_LOAD_FAILED) {
_XnrmIsActive_fn _XnrmIsActive = (_XnrmIsActive_fn)
PR_FindFunctionSymbol(mXineramalib, "XineramaIsActive");
}
if (mXineramalib && mXineramalib != SCREEN_MANAGER_LIBRARY_LOAD_FAILED) {
_XnrmIsActive_fn _XnrmIsActive = (_XnrmIsActive_fn)
PR_FindFunctionSymbol(mXineramalib, "XineramaIsActive");
_XnrmQueryScreens_fn _XnrmQueryScreens = (_XnrmQueryScreens_fn)
PR_FindFunctionSymbol(mXineramalib, "XineramaQueryScreens");
// get the number of screens via xinerama
if (_XnrmIsActive && _XnrmQueryScreens &&
_XnrmIsActive(GDK_DISPLAY())) {
screenInfo = _XnrmQueryScreens(GDK_DISPLAY(), &numScreens);
}
_XnrmQueryScreens_fn _XnrmQueryScreens = (_XnrmQueryScreens_fn)
PR_FindFunctionSymbol(mXineramalib, "XineramaQueryScreens");
// get the number of screens via xinerama
if (_XnrmIsActive && _XnrmQueryScreens &&
_XnrmIsActive(GDK_DISPLAY())) {
screenInfo = _XnrmQueryScreens(GDK_DISPLAY(), &numScreens);
}
// screenInfo == NULL if either Xinerama couldn't be loaded or
// isn't running on the current display
if (!screenInfo) {
nsRefPtr<nsScreenGtk> screen = new nsScreenGtk();
}
// screenInfo == NULL if either Xinerama couldn't be loaded or
// isn't running on the current display
if (!screenInfo) {
nsRefPtr<nsScreenGtk> screen;
numScreens = 1;
if (mCachedScreenArray.Count() > 0) {
screen = static_cast<nsScreenGtk*>(mCachedScreenArray[0]);
} else {
screen = new nsScreenGtk();
if (!screen || !mCachedScreenArray.AppendObject(screen)) {
return NS_ERROR_OUT_OF_MEMORY;
}
screen->Init();
}
// If Xinerama is enabled and there's more than one screen, fill
// in the info for all of the screens. If that's not the case
// then nsScreenGTK() defaults to the screen width + height
else {
screen->Init(mRootWindow);
}
// If Xinerama is enabled and there's more than one screen, fill
// in the info for all of the screens. If that's not the case
// then nsScreenGTK() defaults to the screen width + height
else {
#ifdef DEBUG
printf("Xinerama superpowers activated for %d screens!\n", numScreens);
printf("Xinerama superpowers activated for %d screens!\n", numScreens);
#endif
for (int i = 0; i < numScreens; ++i) {
nsRefPtr<nsScreenGtk> screen = new nsScreenGtk();
for (int i = 0; i < numScreens; ++i) {
nsRefPtr<nsScreenGtk> screen;
if (mCachedScreenArray.Count() > i) {
screen = static_cast<nsScreenGtk*>(mCachedScreenArray[i]);
} else {
screen = new nsScreenGtk();
if (!screen || !mCachedScreenArray.AppendObject(screen)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// initialize this screen object
screen->Init(&screenInfo[i]);
}
}
if (screenInfo) {
XFree(screenInfo);
// initialize this screen object
screen->Init(&screenInfo[i]);
}
}
// Remove any screens that are no longer present.
while (mCachedScreenArray.Count() > numScreens) {
mCachedScreenArray.RemoveObjectAt(mCachedScreenArray.Count() - 1);
}
if (screenInfo) {
XFree(screenInfo);
}
return NS_OK;
}

View File

@ -44,6 +44,8 @@
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "prlink.h"
#include "gdk/gdk.h"
#include <X11/Xlib.h>
//------------------------------------------------------------------------
@ -56,14 +58,22 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSISCREENMANAGER
Atom NetWorkareaAtom() { return mNetWorkareaAtom; }
// For internal use, or reinitialization from change notification.
nsresult Init();
private:
nsresult EnsureInit(void);
nsresult EnsureInit();
// Cached screen array. Its length is the number of screens we have.
nsCOMArray<nsIScreen> mCachedScreenArray;
PRLibrary *mXineramalib;
GdkWindow *mRootWindow;
Atom mNetWorkareaAtom;
};
#endif // nsScreenManagerGtk_h___