x11_factory.cpp 9.58 KB
Newer Older
1 2 3
/*****************************************************************************
 * x11_factory.cpp
 *****************************************************************************
4
 * Copyright (C) 2003 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8
 *          Olivier Teulière <ipkiss@via.ecp.fr>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26
 *****************************************************************************/

#ifdef X11_SKINS

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
27
#include <errno.h>
28 29 30
#include <unistd.h>
#include <dirent.h>
#include <X11/Xlib.h>
31
#include <X11/extensions/Xinerama.h>
32 33 34 35 36

#include "x11_factory.hpp"
#include "x11_display.hpp"
#include "x11_graphics.hpp"
#include "x11_loop.hpp"
Clément Stenac's avatar
Clément Stenac committed
37
#include "x11_popup.hpp"
38 39 40 41
#include "x11_timer.hpp"
#include "x11_window.hpp"
#include "x11_tooltip.hpp"

42
#include "../src/generic_window.hpp"
43

44 45 46
#include <vlc_common.h>
#include <vlc_xlib.h>

47
X11Factory::X11Factory( intf_thread_t *pIntf ): OSFactory( pIntf ),
48
    m_pDisplay( NULL ), m_pTimerLoop( NULL ), m_dirSep( "/" )
49 50 51 52 53 54 55 56 57 58 59 60 61 62
{
    // see init()
}


X11Factory::~X11Factory()
{
    delete m_pTimerLoop;
    delete m_pDisplay;
}


bool X11Factory::init()
{
Erwan Tulou's avatar
Erwan Tulou committed
63
    // make sure xlib is safe-thread
64
    if( !vlc_xlib_init( VLC_OBJECT( getIntf() ) ) )
65
    {
Erwan Tulou's avatar
Erwan Tulou committed
66
        msg_Err( getIntf(), "initializing xlib for multi-threading failed" );
67 68
        return false;
    }
Erwan Tulou's avatar
Erwan Tulou committed
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    // Create the X11 display
    m_pDisplay = new X11Display( getIntf() );

    // Get the display
    Display *pDisplay = m_pDisplay->getDisplay();
    if( pDisplay == NULL )
    {
        // Initialization failed
        return false;
    }

    // Create the timer loop
    m_pTimerLoop = new X11TimerLoop( getIntf(),
                                     ConnectionNumber( pDisplay ) );

85
    // Initialize the resource path
Erwan Tulou's avatar
Erwan Tulou committed
86
    char *datadir = config_GetUserDir( VLC_DATA_DIR );
87
    m_resourcePath.push_back( (std::string)datadir + "/skins2" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
88
    free( datadir );
89
    m_resourcePath.push_back( (std::string)"share/skins2" );
90
    datadir = config_GetDataDir();
91
    m_resourcePath.push_back( (std::string)datadir + "/skins2" );
92
    free( datadir );
93

94 95 96
    // Determine the monitor geometry
    getDefaultGeometry( &m_screenWidth, &m_screenHeight );

97 98 99 100 101 102 103 104 105 106 107 108 109
    // list all available monitors
    int num_screen;
    XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num_screen );
    if( info )
    {
        msg_Dbg( getIntf(), "number of monitors detected : %i", num_screen );
        for( int i = 0; i < num_screen; i++ )
            msg_Dbg( getIntf(), "  monitor #%i : %ix%i at +%i+%i",
                                i, info[i].width, info[i].height,
                                info[i].x_org, info[i].y_org );
        XFree( info );
    }

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    return true;
}


OSGraphics *X11Factory::createOSGraphics( int width, int height )
{
    return new X11Graphics( getIntf(), *m_pDisplay, width, height );
}


OSLoop *X11Factory::getOSLoop()
{
    return X11Loop::instance( getIntf(), *m_pDisplay );
}


void X11Factory::destroyOSLoop()
{
    X11Loop::destroy( getIntf() );
}

131 132 133 134 135
void X11Factory::minimize()
{
    XIconifyWindow( m_pDisplay->getDisplay(), m_pDisplay->getMainWindow(),
                    DefaultScreen( m_pDisplay->getDisplay() ) );
}
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
void X11Factory::restore()
{
    // TODO
}

void X11Factory::addInTray()
{
    // TODO
}

void X11Factory::removeFromTray()
{
    // TODO
}

152 153 154 155 156 157 158 159 160 161
void X11Factory::addInTaskBar()
{
    // TODO
}

void X11Factory::removeFromTaskBar()
{
    // TODO
}

162
OSTimer *X11Factory::createOSTimer( CmdGeneric &rCmd )
163
{
164
    return new X11Timer( getIntf(), rCmd );
165 166 167 168
}


OSWindow *X11Factory::createOSWindow( GenericWindow &rWindow, bool dragDrop,
169 170
                                      bool playOnDrop, OSWindow *pParent,
                                      GenericWindow::WindowType_t type )
171 172
{
    return new X11Window( getIntf(), rWindow, *m_pDisplay, dragDrop,
173
                          playOnDrop, (X11Window*)pParent, type );
174 175 176 177 178 179 180 181 182
}


OSTooltip *X11Factory::createOSTooltip()
{
    return new X11Tooltip( getIntf(), *m_pDisplay );
}


183 184 185 186 187 188
OSPopup *X11Factory::createOSPopup()
{
    return new X11Popup( getIntf(), *m_pDisplay );
}


189 190
int X11Factory::getScreenWidth() const
{
191
    return m_screenWidth;
192 193 194 195 196
}


int X11Factory::getScreenHeight() const
{
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    return m_screenHeight;
}


void X11Factory::getMonitorInfo( const GenericWindow &rWindow,
                                 int* p_x, int* p_y,
                                 int* p_width, int* p_height ) const
{
    // initialize to default geometry
    *p_x = 0;
    *p_y = 0;
    *p_width = getScreenWidth();
    *p_height = getScreenHeight();

    // Use Xinerama to determine the monitor where the video
    // mostly resides (biggest surface)
213
    Display *pDisplay = m_pDisplay->getDisplay();
214 215 216 217 218 219 220 221 222 223 224 225 226
    Window wnd = (Window)rWindow.getOSHandle();
    Window root = DefaultRootWindow( pDisplay );
    Window child_wnd;

    int x, y;
    unsigned int w, h, border, depth;
    XGetGeometry( pDisplay, wnd, &root, &x, &y, &w, &h, &border, &depth );
    XTranslateCoordinates( pDisplay, wnd, root, 0, 0, &x, &y, &child_wnd );

    int num;
    XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
    if( info )
    {
227
        Region reg1 = XCreateRegion();
228
        XRectangle rect1 = { (short)x, (short)y, (unsigned short)w, (unsigned short)h };
229 230
        XUnionRectWithRegion( &rect1, reg1, reg1 );

231 232 233 234
        unsigned int surface = 0;
        for( int i = 0; i < num; i++ )
        {
            Region reg2 = XCreateRegion();
235
            XRectangle rect2 = { info[i].x_org, info[i].y_org,
236
                                 (unsigned short)info[i].width, (unsigned short)info[i].height };
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
            XUnionRectWithRegion( &rect2, reg2, reg2 );

            Region reg = XCreateRegion();
            XIntersectRegion( reg1, reg2, reg );
            XRectangle rect;
            XClipBox( reg, &rect );
            unsigned int surf = rect.width * rect.height;
            if( surf > surface )
            {
               surface = surf;
               *p_x = info[i].x_org;
               *p_y = info[i].y_org;
               *p_width = info[i].width;
               *p_height = info[i].height;
            }
252 253
            XDestroyRegion( reg );
            XDestroyRegion( reg2 );
254
        }
255
        XDestroyRegion( reg1 );
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
        XFree( info );
    }
}


void X11Factory::getMonitorInfo( int numScreen,
                                 int* p_x, int* p_y,
                                 int* p_width, int* p_height ) const
{
    // initialize to default geometry
    *p_x = 0;
    *p_y = 0;
    *p_width = getScreenWidth();
    *p_height = getScreenHeight();

    // try to detect the requested screen via Xinerama
    if( numScreen >= 0 )
    {
        int num;
        Display *pDisplay = m_pDisplay->getDisplay();
        XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
        if( info )
        {
            if( numScreen < num )
            {
                *p_x = info[numScreen].x_org;
                *p_y = info[numScreen].y_org;
                *p_width = info[numScreen].width;
                *p_height = info[numScreen].height;
            }
            XFree( info );
        }
    }
}


void X11Factory::getDefaultGeometry( int* p_width, int* p_height ) const
{
    Display *pDisplay = m_pDisplay->getDisplay();

    // Initialize to defaults
297
    int screen = DefaultScreen( pDisplay );
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    *p_width = DisplayWidth( pDisplay, screen );
    *p_height = DisplayHeight( pDisplay, screen );

    // Use Xinerama to restrain to the first monitor instead of the full
    // virtual screen
    int num;
    XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
    if( info )
    {
        for( int i = 0; i < num; i++ )
        {
            if( info[i].x_org == 0 && info[i].y_org == 0 )
            {
                *p_width = info[i].width;
                *p_height = info[i].height;
                break;
            }
        }
        XFree( info );
    }
318 319 320
}


321
SkinsRect X11Factory::getWorkArea() const
322 323
{
    // XXX
324
    return SkinsRect( 0, 0, getScreenWidth(), getScreenHeight() );
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
}


void X11Factory::getMousePos( int &rXPos, int &rYPos ) const
{
    Window rootReturn, childReturn;
    int winx, winy;
    unsigned int xmask;

    Display *pDisplay = m_pDisplay->getDisplay();
    Window root = DefaultRootWindow( pDisplay );
    XQueryPointer( pDisplay, root, &rootReturn, &childReturn,
                   &rXPos, &rYPos, &winx, &winy, &xmask );
}


341
void X11Factory::rmDir( const std::string &rPath )
342 343 344 345 346 347 348 349
{
    struct dirent *file;
    DIR *dir;

    dir = opendir( rPath.c_str() );
    if( !dir ) return;

    // Parse the directory and remove everything it contains
350
    while( (file = readdir( dir )) )
351
    {
352
        std::string filename = file->d_name;
353 354 355 356 357 358 359 360 361

        // Skip "." and ".."
        if( filename == "." || filename == ".." )
        {
            continue;
        }

        filename = rPath + "/" + filename;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
362
        if( rmdir( filename.c_str() ) && errno == ENOTDIR )
363 364 365 366 367 368 369 370 371 372 373
            unlink( filename.c_str() );
    }

    // Close the directory
    closedir( dir );

    // And delete it
    rmdir( rPath.c_str() );
}

#endif