LCOV - code coverage report
Current view: directory - widget/gtk2 - nsScreenManagerGtk.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 116 0 0.0 %
Date: 2012-06-02 Functions: 13 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2000
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Sylvain Pasche <sylvain.pasche@gmail.com>
      24                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsScreenManagerGtk.h"
      41                 : #include "nsScreenGtk.h"
      42                 : #include "nsIComponentManager.h"
      43                 : #include "nsRect.h"
      44                 : #include "nsAutoPtr.h"
      45                 : 
      46                 : #define SCREEN_MANAGER_LIBRARY_LOAD_FAILED ((PRLibrary*)1)
      47                 : 
      48                 : #ifdef MOZ_X11
      49                 : #include <gdk/gdkx.h>
      50                 : // prototypes from Xinerama.h
      51                 : typedef Bool (*_XnrmIsActive_fn)(Display *dpy);
      52                 : typedef XineramaScreenInfo* (*_XnrmQueryScreens_fn)(Display *dpy, int *number);
      53                 : #endif
      54                 : 
      55                 : #include <gtk/gtk.h>
      56                 : 
      57                 : 
      58                 : static GdkFilterReturn
      59               0 : root_window_event_filter(GdkXEvent *aGdkXEvent, GdkEvent *aGdkEvent,
      60                 :                          gpointer aClosure)
      61                 : {
      62               0 :   nsScreenManagerGtk *manager = static_cast<nsScreenManagerGtk*>(aClosure);
      63                 : #ifdef MOZ_X11
      64               0 :   XEvent *xevent = static_cast<XEvent*>(aGdkXEvent);
      65                 : 
      66                 :   // See comments in nsScreenGtk::Init below.
      67               0 :   switch (xevent->type) {
      68                 :     case ConfigureNotify:
      69               0 :       manager->Init();
      70               0 :       break;
      71                 :     case PropertyNotify:
      72                 :       {
      73               0 :         XPropertyEvent *propertyEvent = &xevent->xproperty;
      74               0 :         if (propertyEvent->atom == manager->NetWorkareaAtom()) {
      75               0 :           manager->Init();
      76                 :         }
      77                 :       }
      78               0 :       break;
      79                 :     default:
      80               0 :       break;
      81                 :   }
      82                 : #endif
      83                 : 
      84               0 :   return GDK_FILTER_CONTINUE;
      85                 : }
      86                 : 
      87               0 : nsScreenManagerGtk :: nsScreenManagerGtk ( )
      88                 :   : mXineramalib(nsnull)
      89               0 :   , mRootWindow(nsnull)
      90                 : {
      91                 :   // nothing else to do. I guess we could cache a bunch of information
      92                 :   // here, but we want to ask the device at runtime in case anything
      93                 :   // has changed.
      94               0 : }
      95                 : 
      96                 : 
      97               0 : nsScreenManagerGtk :: ~nsScreenManagerGtk()
      98                 : {
      99               0 :   if (mRootWindow) {
     100               0 :     gdk_window_remove_filter(mRootWindow, root_window_event_filter, this);
     101               0 :     g_object_unref(mRootWindow);
     102               0 :     mRootWindow = nsnull;
     103                 :   }
     104                 : 
     105                 :   /* XineramaIsActive() registers a callback function close_display()
     106                 :    * in X, which is to be called in XCloseDisplay(). This is the case
     107                 :    * if Xinerama is active, even if only with one screen.
     108                 :    *
     109                 :    * We can't unload libXinerama.so.1 here because this will make
     110                 :    * the address of close_display() registered in X to be invalid and
     111                 :    * it will crash when XCloseDisplay() is called later. */
     112               0 : }
     113                 : 
     114                 : 
     115                 : // addref, release, QI
     116               0 : NS_IMPL_ISUPPORTS1(nsScreenManagerGtk, nsIScreenManager)
     117                 : 
     118                 : 
     119                 : // this function will make sure that everything has been initialized.
     120                 : nsresult
     121               0 : nsScreenManagerGtk :: EnsureInit()
     122                 : {
     123               0 :   if (mCachedScreenArray.Count() > 0)
     124               0 :     return NS_OK;
     125                 : 
     126                 : #if GTK_CHECK_VERSION(2,2,0)
     127               0 :   mRootWindow = gdk_get_default_root_window();
     128                 : #else
     129                 :   mRootWindow = GDK_ROOT_PARENT();
     130                 : #endif // GTK_CHECK_VERSION(2,2,0)
     131               0 :   g_object_ref(mRootWindow);
     132                 : 
     133                 :   // GDK_STRUCTURE_MASK ==> StructureNotifyMask, for ConfigureNotify
     134                 :   // GDK_PROPERTY_CHANGE_MASK ==> PropertyChangeMask, for PropertyNotify
     135                 :   gdk_window_set_events(mRootWindow,
     136               0 :                         GdkEventMask(gdk_window_get_events(mRootWindow) |
     137                 :                                      GDK_STRUCTURE_MASK |
     138               0 :                                      GDK_PROPERTY_CHANGE_MASK));
     139               0 :   gdk_window_add_filter(mRootWindow, root_window_event_filter, this);
     140                 : #ifdef MOZ_X11
     141                 :   mNetWorkareaAtom =
     142               0 :     XInternAtom(GDK_WINDOW_XDISPLAY(mRootWindow), "_NET_WORKAREA", False);
     143                 : #endif
     144                 : 
     145               0 :   return Init();
     146                 : }
     147                 : 
     148                 : nsresult
     149               0 : nsScreenManagerGtk :: Init()
     150                 : {
     151                 : #ifdef MOZ_X11
     152               0 :   XineramaScreenInfo *screenInfo = NULL;
     153                 :   int numScreens;
     154                 : 
     155               0 :   if (!mXineramalib) {
     156               0 :     mXineramalib = PR_LoadLibrary("libXinerama.so.1");
     157               0 :     if (!mXineramalib) {
     158               0 :       mXineramalib = SCREEN_MANAGER_LIBRARY_LOAD_FAILED;
     159                 :     }
     160                 :   }
     161               0 :   if (mXineramalib && mXineramalib != SCREEN_MANAGER_LIBRARY_LOAD_FAILED) {
     162                 :     _XnrmIsActive_fn _XnrmIsActive = (_XnrmIsActive_fn)
     163               0 :         PR_FindFunctionSymbol(mXineramalib, "XineramaIsActive");
     164                 : 
     165                 :     _XnrmQueryScreens_fn _XnrmQueryScreens = (_XnrmQueryScreens_fn)
     166               0 :         PR_FindFunctionSymbol(mXineramalib, "XineramaQueryScreens");
     167                 :         
     168                 :     // get the number of screens via xinerama
     169               0 :     if (_XnrmIsActive && _XnrmQueryScreens &&
     170               0 :         _XnrmIsActive(GDK_DISPLAY())) {
     171               0 :       screenInfo = _XnrmQueryScreens(GDK_DISPLAY(), &numScreens);
     172                 :     }
     173                 :   }
     174                 : 
     175                 :   // screenInfo == NULL if either Xinerama couldn't be loaded or
     176                 :   // isn't running on the current display
     177               0 :   if (!screenInfo || numScreens == 1) {
     178               0 :     numScreens = 1;
     179                 : #endif
     180               0 :     nsRefPtr<nsScreenGtk> screen;
     181                 : 
     182               0 :     if (mCachedScreenArray.Count() > 0) {
     183               0 :       screen = static_cast<nsScreenGtk*>(mCachedScreenArray[0]);
     184                 :     } else {
     185               0 :       screen = new nsScreenGtk();
     186               0 :       if (!screen || !mCachedScreenArray.AppendObject(screen)) {
     187               0 :         return NS_ERROR_OUT_OF_MEMORY;
     188                 :       }
     189                 :     }
     190                 : 
     191               0 :     screen->Init(mRootWindow);
     192                 : #ifdef MOZ_X11
     193                 :   }
     194                 :   // If Xinerama is enabled and there's more than one screen, fill
     195                 :   // in the info for all of the screens.  If that's not the case
     196                 :   // then nsScreenGTK() defaults to the screen width + height
     197                 :   else {
     198                 : #ifdef DEBUG
     199               0 :     printf("Xinerama superpowers activated for %d screens!\n", numScreens);
     200                 : #endif
     201               0 :     for (int i = 0; i < numScreens; ++i) {
     202               0 :       nsRefPtr<nsScreenGtk> screen;
     203               0 :       if (mCachedScreenArray.Count() > i) {
     204               0 :         screen = static_cast<nsScreenGtk*>(mCachedScreenArray[i]);
     205                 :       } else {
     206               0 :         screen = new nsScreenGtk();
     207               0 :         if (!screen || !mCachedScreenArray.AppendObject(screen)) {
     208               0 :           return NS_ERROR_OUT_OF_MEMORY;
     209                 :         }
     210                 :       }
     211                 : 
     212                 :       // initialize this screen object
     213               0 :       screen->Init(&screenInfo[i]);
     214                 :     }
     215                 :   }
     216                 :   // Remove any screens that are no longer present.
     217               0 :   while (mCachedScreenArray.Count() > numScreens) {
     218               0 :     mCachedScreenArray.RemoveObjectAt(mCachedScreenArray.Count() - 1);
     219                 :   }
     220                 : 
     221               0 :   if (screenInfo) {
     222               0 :     XFree(screenInfo);
     223                 :   }
     224                 : #endif
     225                 : 
     226               0 :   return NS_OK;
     227                 : }
     228                 : 
     229                 : 
     230                 : //
     231                 : // ScreenForRect 
     232                 : //
     233                 : // Returns the screen that contains the rectangle. If the rect overlaps
     234                 : // multiple screens, it picks the screen with the greatest area of intersection.
     235                 : //
     236                 : // The coordinates are in pixels (not app units) and in screen coordinates.
     237                 : //
     238                 : NS_IMETHODIMP
     239               0 : nsScreenManagerGtk :: ScreenForRect ( PRInt32 aX, PRInt32 aY,
     240                 :                                       PRInt32 aWidth, PRInt32 aHeight,
     241                 :                                       nsIScreen **aOutScreen )
     242                 : {
     243                 :   nsresult rv;
     244               0 :   rv = EnsureInit();
     245               0 :   if (NS_FAILED(rv)) {
     246               0 :     NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from ScreenForRect");
     247               0 :     return rv;
     248                 :   }
     249                 :   // which screen ( index from zero ) should we return?
     250               0 :   PRUint32 which = 0;
     251                 :   // Optimize for the common case.  If the number of screens is only
     252                 :   // one then this will fall through with which == 0 and will get the
     253                 :   // primary screen.
     254               0 :   if (mCachedScreenArray.Count() > 1) {
     255                 :     // walk the list of screens and find the one that has the most
     256                 :     // surface area.
     257               0 :     PRUint32 area = 0;
     258               0 :     nsIntRect windowRect(aX, aY, aWidth, aHeight);
     259               0 :     for (PRInt32 i = 0, i_end = mCachedScreenArray.Count(); i < i_end; ++i) {
     260                 :       PRInt32  x, y, width, height;
     261               0 :       x = y = width = height = 0;
     262               0 :       mCachedScreenArray[i]->GetRect(&x, &y, &width, &height);
     263                 :       // calculate the surface area
     264               0 :       nsIntRect screenRect(x, y, width, height);
     265               0 :       screenRect.IntersectRect(screenRect, windowRect);
     266               0 :       PRUint32 tempArea = screenRect.width * screenRect.height;
     267               0 :       if (tempArea >= area) {
     268               0 :         which = i;
     269               0 :         area = tempArea;
     270                 :       }
     271                 :     }
     272                 :   }
     273               0 :   *aOutScreen = mCachedScreenArray.SafeObjectAt(which);
     274               0 :   NS_IF_ADDREF(*aOutScreen);
     275               0 :   return NS_OK;
     276                 :     
     277                 : } // ScreenForRect
     278                 : 
     279                 : 
     280                 : //
     281                 : // GetPrimaryScreen
     282                 : //
     283                 : // The screen with the menubar/taskbar. This shouldn't be needed very
     284                 : // often.
     285                 : //
     286                 : NS_IMETHODIMP 
     287               0 : nsScreenManagerGtk :: GetPrimaryScreen(nsIScreen * *aPrimaryScreen) 
     288                 : {
     289                 :   nsresult rv;
     290               0 :   rv =  EnsureInit();
     291               0 :   if (NS_FAILED(rv)) {
     292               0 :     NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from GetPrimaryScreen");
     293               0 :     return rv;
     294                 :   }
     295               0 :   *aPrimaryScreen = mCachedScreenArray.SafeObjectAt(0);
     296               0 :   NS_IF_ADDREF(*aPrimaryScreen);
     297               0 :   return NS_OK;
     298                 :   
     299                 : } // GetPrimaryScreen
     300                 : 
     301                 : 
     302                 : //
     303                 : // GetNumberOfScreens
     304                 : //
     305                 : // Returns how many physical screens are available.
     306                 : //
     307                 : NS_IMETHODIMP
     308               0 : nsScreenManagerGtk :: GetNumberOfScreens(PRUint32 *aNumberOfScreens)
     309                 : {
     310                 :   nsresult rv;
     311               0 :   rv = EnsureInit();
     312               0 :   if (NS_FAILED(rv)) {
     313               0 :     NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from GetNumberOfScreens");
     314               0 :     return rv;
     315                 :   }
     316               0 :   *aNumberOfScreens = mCachedScreenArray.Count();
     317               0 :   return NS_OK;
     318                 :   
     319                 : } // GetNumberOfScreens
     320                 : 
     321                 : NS_IMETHODIMP
     322               0 : nsScreenManagerGtk :: ScreenForNativeWidget (void *aWidget, nsIScreen **outScreen)
     323                 : {
     324                 :   nsresult rv;
     325               0 :   rv = EnsureInit();
     326               0 :   if (NS_FAILED(rv)) {
     327               0 :     NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from ScreenForNativeWidget");
     328               0 :     return rv;
     329                 :   }
     330                 : 
     331               0 :   if (mCachedScreenArray.Count() > 1) {
     332                 :     // I don't know how to go from GtkWindow to nsIScreen, especially
     333                 :     // given xinerama and stuff, so let's just do this
     334                 :     gint x, y, width, height, depth;
     335               0 :     x = y = width = height = 0;
     336                 : 
     337               0 :     gdk_window_get_geometry(GDK_WINDOW(aWidget), &x, &y, &width, &height,
     338               0 :                             &depth);
     339               0 :     gdk_window_get_origin(GDK_WINDOW(aWidget), &x, &y);
     340               0 :     rv = ScreenForRect(x, y, width, height, outScreen);
     341                 :   } else {
     342               0 :     rv = GetPrimaryScreen(outScreen);
     343                 :   }
     344                 : 
     345               0 :   return rv;
     346                 : }

Generated by: LCOV version 1.7