view Gui/win32/gui.c @ 22386:6c9a391ca7cb

clarify quorum and majority requirements in respect to debians voting system maybe we should just copy and paste the description from debian and add these into it?
author michael
date Thu, 01 Mar 2007 22:58:31 +0000
parents 9f5657a1dbf7
children 458b7f1386f3
line wrap: on
line source

/*
  MPlayer Gui for win32
  Copyright (c) 2003 Sascha Sommer <saschasommer@freenet.de>
  Copyright (c) 2006 Erik Augustson <erik_27can@yahoo.com>
  Copyright (c) 2006 Gianluigi Tiesi <sherpya@netfarm.it>

  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
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>
#include <version.h>
#include <mplayer.h>
#include <mp_msg.h>
#include <help_mp.h>
#include <input/input.h>
#include <input/mouse.h>
#include <osdep/keycodes.h>
#include <stream/stream.h>
#include <libvo/video_out.h>
#include <interface.h>
#include "gui.h"
#include "wincfg.h"
#include "dialogs.h"

// HACK around bug in old mingw
#undef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)

#ifndef WM_XBUTTONDOWN
# define WM_XBUTTONDOWN    0x020B
# define WM_XBUTTONUP      0x020C
# define WM_XBUTTONDBLCLK  0x020D
#endif

/* Globals / Externs */
extern void renderinfobox(skin_t *skin, window_priv_t *priv);
extern void renderwidget(skin_t *skin, image *dest, widget *item, int state);
extern void mplayer_put_key(int code);
extern void print_version(void);
extern int WinID;
float sub_aspect;

DWORD oldtime;
NOTIFYICONDATA nid;
int console_state = 0;
play_tree_t *playtree = NULL;
m_config_t* mconfig = NULL;

static HBRUSH    colorbrush = NULL;           //Handle to colorkey brush
static COLORREF windowcolor = RGB(255,0,255); //Windowcolor == colorkey

void console_toggle(void)
{
    if (console_state)
    {
        FreeConsole();
        console = 0;
        console_state = 0;
    }
    else
    {
        /* This code comes from: http://dslweb.nwnexus.com/~ast/dload/guicon.htm */
        CONSOLE_SCREEN_BUFFER_INFO coninfo;
        FILE *fp;
        HWND hwnd = NULL;
        console = 1;
        AllocConsole();
        SetConsoleTitle(MP_TITLE);

        /* disable the close button for now */
        while (!hwnd)
        {
            hwnd = FindWindow(NULL, MP_TITLE);
            Sleep(100);
        }
        DeleteMenu(GetSystemMenu(hwnd, 0), SC_CLOSE, MF_BYCOMMAND);

        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
        coninfo.dwSize.Y = 1000;
        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
        fp = freopen("con", "w", stdout);
        *stdout = *fp;
        setvbuf(stdout, NULL, _IONBF, 0);
        fp = freopen("con", "r", stdin);
        *stdin = *fp;
        setvbuf(stdin, NULL, _IONBF, 0);
        fp = freopen("con", "w", stdout);
        *stderr = *fp;
        setvbuf(stderr, NULL, _IONBF, 0);
        print_version();
        console_state = 1;
    }
}

void capitalize(char *filename)
{
    unsigned int i;
    BOOL cap = TRUE;
    for (i=0; i < strlen(filename); i++)
    {
        if (cap)
        {
            cap = FALSE;
            filename[i] = toupper(filename[i]);
        }
        else if (filename[i] == ' ')
            cap = TRUE;
        else
            filename[i] = tolower(filename[i]);
    }
}

static image *get_drawground(HWND hwnd)
{
    gui_t * gui = (gui_t *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
    unsigned int i;
    if(!gui) return NULL;
    for(i=0; i<gui->window_priv_count; i++)
        if(gui->window_priv[i]->hwnd==hwnd)
            return &gui->window_priv[i]->img;
    return NULL;
}

static HBITMAP get_bitmap(HWND hwnd)
{
    gui_t *gui = (gui_t *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
    unsigned int i;
    if(!gui) return NULL;
    for(i=0; i<gui->window_priv_count; i++)
        if(gui->window_priv[i]->hwnd == hwnd)
            return gui->window_priv[i]->bitmap;
    return NULL;
}

static int get_windowtype(HWND hwnd)
{
    gui_t *gui = (gui_t *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
    unsigned int i;
    if(!gui) return -1;
    for(i=0; i<gui->window_priv_count; i++)
        if(gui->window_priv[i]->hwnd == hwnd)
            return gui->window_priv[i]->type;
    return -1;
}

static void uninit(gui_t *gui)
{
    if(gui->skin) destroy_window(gui);
    if(gui->playlist) gui->playlist->free_playlist(gui->playlist);
    gui->playlist = NULL;
}

/*
    the gui message handler
    tries to handle the incoming messages
    and passes them to the player's message handler if it can't handle them
*/
static void handlemsg(HWND hWnd, int msg)
{
    gui_t *gui = (gui_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
    if(msg == evNone) return;

    switch(msg)
    {
        case evLoadPlay:
        case evLoad:
            if(display_openfilewindow(gui, 0) && (msg == evLoadPlay))
                handlemsg(hWnd, evDropFile);
            return;
        case evLoadSubtitle:
            display_opensubtitlewindow(gui);
            break;
        case evPreferences:
            display_prefswindow(gui);
            return;
        case evPlayList:
            display_playlistwindow(gui);
            return;
        case evSkinBrowser:
            display_skinbrowser(gui);
            break;
        case evEqualizer:
            display_eqwindow(gui);
            break;
        case evAbout:
            MessageBox(hWnd, COPYRIGHT, "About", MB_OK);
            break;
        case evIconify:
            ShowWindow(hWnd, SW_MINIMIZE);
            break;
        case evIncVolume:
            mplayer_put_key(KEY_VOLUME_UP);
            break;
        case evDecVolume:
            mplayer_put_key(KEY_VOLUME_DOWN);
            break;
        default:
            mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] received msg %s (%i)\n", gui->skin->geteventname(msg), msg);
            break;
    }
    gui->playercontrol(msg);
}

static widget *clickedinsidewidget(gui_t *gui, int window, int x, int y)
{
    unsigned int i;
    widget *item;
    for(i=0; i<gui->skin->widgetcount; i++)
    {
        item = gui->skin->widgets[i];
        if((item->window == window) && (item->x <= x) && (item->x + item->width >= x) &&
           (item->y <= y) && (item->y + item->height >= y))
            return item;
    }
    return NULL;
}

/* updates sliders and the display */
static void updatedisplay(gui_t *gui, HWND hwnd)
{
    unsigned int i;
    window_priv_t *priv = NULL;
    DWORD time = timeGetTime();

    if(!hwnd) return;

    /* load all potmeters hpotmeters */
    for(i=0; i<gui->skin->widgetcount; i++)
    {
        if(gui->skin->widgets[i]->type == tyHpotmeter || gui->skin->widgets[i]->type == tyPotmeter)
        {
            if(gui->skin->widgets[i]->msg == evSetVolume)
                gui->skin->widgets[i]->value = guiIntfStruct.Volume;
            else if(gui->skin->widgets[i]->msg == evSetMoviePosition)
                gui->skin->widgets[i]->value = guiIntfStruct.Position;
            else if(gui->skin->widgets[i]->msg == evSetBalance)
                gui->skin->widgets[i]->value = guiIntfStruct.Balance;
            if(gui->skin->widgets[i]->window == get_windowtype(hwnd))
                renderwidget(gui->skin, get_drawground(hwnd), gui->skin->widgets[i],
                             gui->skin->widgets[i]->pressed ? 0 : 1);
        }
        /* update some buttons */
        if(gui->skin->widgets[i]->type == tyButton && gui->skin->widgets[i]->window == get_windowtype(hwnd))
        {
            if(gui->skin->widgets[i]->msg == evPlaySwitchToPause)
            {
                gui->skin->widgets[i]->value = guiIntfStruct.Playing;
                    renderwidget(gui->skin, get_drawground(hwnd), gui->skin->widgets[i],
                                 guiIntfStruct.Playing == 1 ? 0 : 1);
            }
            if(gui->skin->widgets[i]->msg == evMute)
            {
                gui->skin->widgets[i]->value = guiIntfStruct.Volume;
                    renderwidget(gui->skin, get_drawground(hwnd), gui->skin->widgets[i],
                                 guiIntfStruct.Volume == 0.0f ? 0 : 1);
            }
        }
    }

    /* updating the display once a 100.second is enough imo */
    if((time - oldtime) < 100) return;
    oldtime=time;

    /* suppress directx's fullscreen window when using the sub window */
    if(sub_window && &video_driver_list[0] && strstr("directx", video_driver_list[0]))
    {
        HWND hWndFS = NULL; //handle to directx's fullscreen window
        if(hWndFS == NULL)
        {
            hWndFS = FindWindow(NULL, "MPlayer Fullscreen");
            if(hWndFS != NULL) DestroyWindow(hWndFS); //sub window handles fullscreen
        }
    }

    for (i=0; i<gui->window_priv_count; i++)
    {
        if(gui->window_priv[i]->hwnd == hwnd)
            priv=gui->window_priv[i];
    }// Sherpya
    /* display the status msgs */
    renderinfobox(gui->skin, priv);
    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
}

static LRESULT CALLBACK SubProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    gui_t *gui = (gui_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
    if (gui && (gui->subwindow != hWnd)) return FALSE;

    switch (message)
    {
        case WM_CLOSE:
            handlemsg(hWnd, evExit);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_KEYDOWN:
        {
            switch(wParam)
            {
                case VK_LEFT:
                    mplayer_put_key(KEY_LEFT);
                    break;
                case VK_UP:
                    mplayer_put_key(KEY_UP);
                    break;
                case VK_RIGHT:
                    mplayer_put_key(KEY_RIGHT);
                    break;
                case VK_DOWN:
                    mplayer_put_key(KEY_DOWN);
                    break;
                case VK_TAB:
                    mplayer_put_key(KEY_TAB);
                    break;
                case VK_BACK:
                    mplayer_put_key(KEY_BS);
                    break;
                case VK_DELETE:
                    mplayer_put_key(KEY_DELETE);
                    break;
                case VK_INSERT:
                    mplayer_put_key(KEY_INSERT);
                    break;
                case VK_HOME:
                    mplayer_put_key(KEY_HOME);
                    break;
                case VK_END:
                    mplayer_put_key(KEY_END);
                    break;
                case VK_PRIOR:
                    mplayer_put_key(KEY_PAGE_UP);
                    break;
                case VK_NEXT:
                    mplayer_put_key(KEY_PAGE_DOWN);
                    break;
                case VK_ESCAPE:
                    mplayer_put_key(KEY_ESC);
                    break;
            }
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case IDEXIT:
                    PostQuitMessage(0);
                    handlemsg(hWnd, evExit);
                    break;
                case IDFILE_OPEN:
                    handlemsg(hWnd, evLoadPlay);
                    break;
                case IDURL_OPEN:
                    display_openurlwindow(gui, 0);
                    break;
                case IDDIR_OPEN:
                {
                    static char path[MAX_PATH];
                    BROWSEINFO bi;
                    LPITEMIDLIST pidl;
                    memset(&bi, 0, sizeof(BROWSEINFO));
                    bi.lpszTitle = "Choose a Directory...";
                    pidl = SHBrowseForFolder(&bi);
                    if (SHGetPathFromIDList(pidl, path))
                    {
                        gui->playlist->clear_playlist(gui->playlist);
                        adddirtoplaylist(gui->playlist, path, TRUE);
                        gui->startplay(gui);
                    }
                    break;
                }
                case ID_PTRACK:
                    handlemsg(hWnd, evPrev);
                    break;
                case ID_SEEKB:
                    handlemsg(hWnd, evBackward10sec);
                    break;
                case ID_PLAY:
                    handlemsg(hWnd, evPlaySwitchToPause);
                    break;
                case ID_STOP:
                    handlemsg(hWnd, evStop);
                    break;
                case ID_SEEKF:
                    handlemsg(hWnd, evForward10sec);
                    break;
                case ID_NTRACK:
                    handlemsg(hWnd, evNext);
                    break;
#ifdef USE_DVDREAD
                case ID_CHAPTERSEL:
                    display_chapterselwindow(gui);
                    break;
#endif
                case ID_FULLSCREEN:
                    mp_input_queue_cmd(mp_input_parse_cmd("vo_fullscreen"));
                    break;
                case ID_MUTE:
                    mp_input_queue_cmd(mp_input_parse_cmd("mute"));
                    break;
                case ID_ASPECT1:
                    mp_input_queue_cmd(mp_input_parse_cmd("switch_ratio 1.777777"));
                    break;
                case ID_ASPECT2:
                    mp_input_queue_cmd(mp_input_parse_cmd("switch_ratio 1.333333"));
                    break;
                case ID_ASPECT3:
                    mp_input_queue_cmd(mp_input_parse_cmd("switch_ratio 2.35"));
                    break;
                case ID_ASPECT4:
                    mp_input_queue_cmd(mp_input_parse_cmd("switch_ratio 0"));
                    break;
                case IDSUB_TOGGLE:
                    mp_input_queue_cmd(mp_input_parse_cmd("sub_visibility"));
                    break;
                case IDSUB_CYCLE:
                    mp_input_queue_cmd(mp_input_parse_cmd("sub_select"));
                    break;
            }
            return 0;
        }
        case WM_CHAR:
            mplayer_put_key(wParam);
            break;
        case WM_DROPFILES:
        {
            if(!lParam)
            {
                char file[MAX_PATH];
                int filecount = DragQueryFile((HDROP) wParam, -1, file, MAX_PATH);
                int i;
                for(i=0; i<filecount; i++)
                {
                    DragQueryFile((HDROP) wParam, i, file, MAX_PATH);
                    if(!parse_filename(file, playtree, mconfig, 1))
                        gui->playlist->add_track(gui->playlist, file, NULL, NULL, 0);
                }
                DragFinish((HDROP) wParam);
                handlemsg(hWnd, evDropFile);
            }
            else
            {
                gui->playlist->clear_playlist(gui->playlist);
                gui->playlist->add_track(gui->playlist, (const char *) wParam, NULL, NULL, 0);
                handlemsg(hWnd, evDropFile);
            }
            SetForegroundWindow(gui->subwindow);
            return 0;
        }
        case WM_LBUTTONDOWN:
        {
            if(!vo_nomouse_input)
               mplayer_put_key(MOUSE_BTN0);
            break;
        }
        case WM_MBUTTONDOWN:
        {
            if(!vo_nomouse_input)
               mplayer_put_key(MOUSE_BTN1);
            break;
        }
        case WM_RBUTTONDOWN:
        {
            POINT point;
            point.x = GET_X_LPARAM(lParam);
            point.y = GET_Y_LPARAM(lParam);
            ClientToScreen(hWnd, &point);
            if(guiIntfStruct.StreamType == STREAMTYPE_DVD)
                EnableMenuItem(gui->dvdmenu, ID_CHAPTERSEL, MF_BYCOMMAND | MF_ENABLED);
            TrackPopupMenu(gui->submenu, 0, point.x, point.y, 0, hWnd, NULL);
            return 0;
        }
        case WM_LBUTTONDBLCLK:
        {
            if(!vo_nomouse_input)
                mplayer_put_key(MOUSE_BTN0_DBL);
            break;
        }
        case WM_MBUTTONDBLCLK:
        {
            if(!vo_nomouse_input)
                mplayer_put_key(MOUSE_BTN1_DBL);
            break;
        }
        case WM_RBUTTONDBLCLK:
        {
            if(!vo_nomouse_input)
                mplayer_put_key(MOUSE_BTN2_DBL);
            break;
        }
        case WM_MOUSEWHEEL:
        {
            int x = GET_WHEEL_DELTA_WPARAM(wParam);
            if(vo_nomouse_input)
                break;
            if (x > 0)
                mplayer_put_key(MOUSE_BTN3);
            else
                mplayer_put_key(MOUSE_BTN4);
            break;
        }
        case WM_XBUTTONDOWN:
        {
            if(vo_nomouse_input)
                break;
            if(HIWORD(wParam) == 1)
                mplayer_put_key(MOUSE_BTN5);
            else
                mplayer_put_key(MOUSE_BTN6);
            break;
        }
        case WM_XBUTTONDBLCLK:
        {
            if(vo_nomouse_input)
                break;
            if(HIWORD(wParam) == 1)
                mplayer_put_key(MOUSE_BTN5_DBL);
            else
                mplayer_put_key(MOUSE_BTN6_DBL);
            break;
        }
        case WM_TIMER:
        {
            if(fullscreen) while(ShowCursor(FALSE) >= 0){}
            KillTimer(hWnd, ID_TIMER);
            return 0;
        }
        case WM_MOUSEMOVE:
        {
            ShowCursor(TRUE);
            SetTimer(hWnd, ID_TIMER, 3000, (TIMERPROC) NULL);
            break;
        }
        case WM_WINDOWPOSCHANGED:
        {
            int tmpheight=0;
            static uint32_t rect_width;
            static uint32_t rect_height;
            RECT rd;
            POINT pt;
            pt.x = 0;
            pt.y = 0;
            GetClientRect(hWnd, &rd);
            ClientToScreen(hWnd, &pt);

            rect_width = rd.right - rd.left;
            rect_height = rd.bottom - rd.top;

            /* maintain our aspect ratio */
            tmpheight = ((float)rect_width/sub_aspect);
            tmpheight += tmpheight % 2;
            if(tmpheight > rect_height)
            {
                rect_width = ((float)rect_height*sub_aspect);
                rect_width += rect_width % 2;
            }
            else rect_height = tmpheight;

            rd.right = rd.left + rect_width;
            rd.bottom = rd.top + rect_height;

            AdjustWindowRect(&rd, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0);
            SetWindowPos(hWnd, 0, fullscreen?0:pt.x+rd.left, fullscreen?0:pt.y+rd.top,
                         fullscreen?vo_screenwidth:rd.right-rd.left, fullscreen?vo_screenheight:rd.bottom-rd.top, SWP_NOOWNERZORDER);
            SetForegroundWindow(hWnd);
            return 0;
        }
        case WM_SYSCOMMAND:
        {
            switch(wParam)
            {
                case SC_SCREENSAVE:
                case SC_MONITORPOWER:
                    mp_msg(MSGT_VO, MSGL_V ,"<vo_directx><INFO>killing screensaver\n" );
                    return 0;
            }
            break;
        }
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            RECT rect;
            HDC hdc = BeginPaint(hWnd, &ps);
            HDC hMemDC = CreateCompatibleDC(hdc);
            HBRUSH blackbrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
            int width, height;
            GetClientRect(hWnd, &rect);
            width = rect.right - rect.left;
            height = rect.bottom - rect.top;
            if(guiIntfStruct.Playing == 0)
            {
                int i;
                window *desc = NULL;

                for (i=0; i<gui->skin->windowcount; i++)
                    if(gui->skin->windows[i]->type == wiSub)
                        desc = gui->skin->windows[i];

                SelectObject(hMemDC, get_bitmap(hWnd));
                StretchBlt(hdc, 0, 0, width, height, hMemDC, 0, 0, desc->base->bitmap[0]->width,
                           desc->base->bitmap[0]->height, SRCCOPY);
            } else {
                FillRect(GetDC(hWnd), &rect, fullscreen?blackbrush:colorbrush);
            }
            DeleteDC(hMemDC);
            EndPaint(hWnd, &ps);
            return 0;
        }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

/* Window Proc for the gui Window */
static LRESULT CALLBACK EventProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    gui_t *gui = (gui_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);

    /* Avoid processing when then window doesn't match gui mainwindow */
    if (gui && (gui->mainwindow != hWnd)) return FALSE;

    switch (message)
    {
        case WM_CLOSE:
            handlemsg(hWnd, evExit);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_SYSTRAY:
        {
            switch(lParam)
            {
                POINT cursor;
                case WM_RBUTTONDOWN:
                {
                    GetCursorPos(&cursor);
                    SetForegroundWindow(hWnd);
                    TrackPopupMenu(gui->traymenu, 0, cursor.x, cursor.y, 0, hWnd, NULL);
                    break;
                }
                case WM_MBUTTONDBLCLK:
                case WM_LBUTTONDBLCLK:
                {
                    if(IsWindowVisible(hWnd)) ShowWindow(hWnd, SW_HIDE);
                    else { ShowWindow(hWnd, SW_SHOW); SetForegroundWindow(hWnd); }
                    break;
                }
            }
            break;
        }
        case WM_KEYDOWN:
        {
            switch(wParam)
            {
                case VK_LEFT:
                    mplayer_put_key(KEY_LEFT);
                    break;
                case VK_UP:
                    mplayer_put_key(KEY_UP);
                    break;
                case VK_RIGHT:
                    mplayer_put_key(KEY_RIGHT);
                    break;
                case VK_DOWN:
                    mplayer_put_key(KEY_DOWN);
                    break;
                case VK_TAB:
                    mplayer_put_key(KEY_TAB);
                    break;
                case VK_BACK:
                    mplayer_put_key(KEY_BS);
                    break;
                case VK_DELETE:
                    mplayer_put_key(KEY_DELETE);
                    break;
                case VK_INSERT:
                    mplayer_put_key(KEY_INSERT);
                    break;
                case VK_HOME:
                    mplayer_put_key(KEY_HOME);
                    break;
                case VK_END:
                    mplayer_put_key(KEY_END);
                    break;
                case VK_PRIOR:
                    mplayer_put_key(KEY_PAGE_UP);
                    break;
                case VK_NEXT:
                    mplayer_put_key(KEY_PAGE_DOWN);
                    break;
                case VK_ESCAPE:
                    mplayer_put_key(KEY_ESC);
                    break;
            }
            break;
        }
        case WM_CHAR:
            mplayer_put_key(wParam);
            break;
        case WM_COPYDATA:
        {
            if(lParam)
            {
                PCOPYDATASTRUCT cdData;
                cdData = (PCOPYDATASTRUCT) lParam;
                if(!parse_filename(cdData->lpData, playtree, mconfig, 1))
                    gui->playlist->add_track(gui->playlist, cdData->lpData, NULL, NULL, 0);
                gui->startplay(gui);
            }
            break;
        }
        case WM_DROPFILES:
        {
            if(!lParam)
            {
                char file[MAX_PATH];
                int filecount = DragQueryFile((HDROP) wParam, -1, file, MAX_PATH);
                int i;
                for(i=0; i<filecount; i++)
                {
                    DragQueryFile((HDROP) wParam, i, file, MAX_PATH);
                    if(!parse_filename(file, playtree, mconfig, 1))
                        gui->playlist->add_track(gui->playlist, file, NULL, NULL, 0);
                }
                DragFinish((HDROP) wParam);
                handlemsg(hWnd, evDropFile);
            }
            else
            {
                gui->playlist->clear_playlist(gui->playlist);
                gui->playlist->add_track(gui->playlist, (const char *) wParam, NULL, NULL, 0);
                handlemsg(hWnd, evDropFile);
            }
            SetForegroundWindow(gui->mainwindow);
            return 0;
        }
        case WM_LBUTTONDOWN:
        {
            SetCapture(hWnd);
            gui->mousex = GET_X_LPARAM(lParam);
            gui->mousey = GET_Y_LPARAM(lParam);
            /* inside a widget */
            gui->activewidget = clickedinsidewidget(gui, get_windowtype(hWnd), gui->mousex, gui->mousey);
            if(gui->activewidget)
            {
                gui->activewidget->pressed = 1;
                gui->mousewx = gui->mousex - gui->activewidget->x;
                gui->mousewy = gui->mousey - gui->activewidget->y;
                renderwidget(gui->skin, get_drawground(hWnd), gui->activewidget, 0);
                RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
                handlemsg(hWnd, gui->activewidget->msg);
            }
            break;
        }
        case WM_CAPTURECHANGED:
        {
            if(gui->activewidget)
            {
                gui->activewidget->pressed = 0;
                renderwidget(gui->skin, get_drawground(hWnd), gui->activewidget, 1);
                RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
                gui->activewidget = NULL;
            }
            break;
        }
        case WM_LBUTTONUP:
        {
            ReleaseCapture();
            if(gui->activewidget)
            {
                gui->activewidget->pressed = 0;
                renderwidget(gui->skin, get_drawground(hWnd), gui->activewidget, 1);
                RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
                gui->activewidget = NULL;
            }
            break;
        }
        case WM_RBUTTONDOWN:
        {
            POINT point;
            char device[MAX_PATH];
            char searchpath[MAX_PATH];
            char searchpath2[MAX_PATH];
#ifdef HAVE_LIBCDIO
            char searchpath3[MAX_PATH];
#endif
            int len, pos = 0, cdromdrive = 0;
            UINT errmode;
            point.x = GET_X_LPARAM(lParam);
            point.y = GET_Y_LPARAM(lParam);
            ClientToScreen(hWnd, &point);
            errmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
            while (GetMenuItemCount(gui->diskmenu) > 0)
                DeleteMenu(gui->diskmenu, 0, MF_BYPOSITION);
            len = GetLogicalDriveStrings(MAX_PATH, device);
            while(pos < len)
            {
                if(GetDriveType(device + pos) == DRIVE_CDROM)
                {
                    char volname[MAX_PATH];
                    char menuitem[MAX_PATH];
                    int flags = MF_STRING;
                    mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] checking %s for CD/VCD/SVCD/DVDs\n", device + pos);
                    sprintf(searchpath, "%sVIDEO_TS", device + pos);
                    sprintf(searchpath2, "%sMpegav", device + pos);
#ifdef HAVE_LIBCDIO
                    sprintf(searchpath3, "%sTrack01.cda", device + pos);
#endif
                    if(GetFileAttributes(searchpath) != INVALID_FILE_ATTRIBUTES)
                        flags |= MF_ENABLED;
                    else if(GetFileAttributes(searchpath2) != INVALID_FILE_ATTRIBUTES)
                        flags |= MF_ENABLED;
#ifdef HAVE_LIBCDIO
                    else if(GetFileAttributes(searchpath3) != INVALID_FILE_ATTRIBUTES)
                        flags |= MF_ENABLED;
#endif
                    else
                        flags |= MF_GRAYED;
                    volname[0] = 0;
                    strcpy(menuitem, device + pos);
                    menuitem[strlen(menuitem) - 1]=0;
                    GetVolumeInformation(device + pos, volname, MAX_PATH, NULL, NULL, NULL, NULL, 0);
                    if (strlen(volname))
                    {
                        capitalize(volname);
                        strcat(menuitem, " - ");
                        strcat(menuitem, volname);
                    }
                    AppendMenu(gui->diskmenu, flags, IDPLAYDISK + cdromdrive, menuitem);
                        cdromdrive++;
                }
                pos += strlen(device + pos) + 1;
            }
            SetErrorMode(errmode);
            TrackPopupMenu(gui->menu, 0, point.x, point.y, 0, hWnd, NULL);
            return 0;
        }
        case WM_MOUSEMOVE:
        {
            if(wParam & MK_LBUTTON)
            {
                POINT point;
                RECT rect;
                if(gui->activewidget)
                {
                    widget *item = gui->activewidget;

                    if(item->type == tyHpotmeter)
                    {
                        item->x = GET_X_LPARAM(lParam) - gui->mousewx;
                        item->value = (float)((float)((item->x - item->wx) * 100.0f) / (float)(item->wwidth - item->width));
                    }
                    if(item->type == tyPotmeter)
                    {
                        gui->mousewx = GET_X_LPARAM(lParam) - gui->activewidget->x;
                        item->value = (float) (gui->mousewx * 100.0f) / (float) item->wwidth;
                    }

                    if((item->type == tyPotmeter) || (item->type == tyHpotmeter) || (item->type == tyVpotmeter))
                    {
                        /* Bound checks */
                        if(item->value > 100.0f)
                            item->value = 100.0f;
                        else if(item->value < 0.0f)
                            item->value = 0.0f;

                        if(item->msg == evSetVolume)
                            guiIntfStruct.Volume = (float) item->value;
                        else if(item->msg == evSetMoviePosition)
                            guiIntfStruct.Position = (float) item->value;
                        else if(item->msg == evSetBalance)
                        {
                            /* make the range for 50% a bit bigger, because the sliders for balance usually suck */
                            if((item->value - 50.0f < 1.5f) && (item->value - 50.0f > -1.5f))
                                item->value = 50.0f;
                            guiIntfStruct.Balance = (float) item->value;
                        }
                        updatedisplay(gui, hWnd);
                        handlemsg(hWnd, item->msg);
                    }
                    break;
                }
                point.x = GET_X_LPARAM(lParam);
                point.y = GET_Y_LPARAM(lParam);
                ClientToScreen(hWnd, &point);
                GetWindowRect(hWnd, &rect);
                MoveWindow(hWnd, point.x - gui->mousex, point.y - gui->mousey,
                           rect.right-rect.left,rect.bottom-rect.top,TRUE);
                break;
            }
            break;
        }
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case IDEXIT:
                    PostQuitMessage(0);
                    handlemsg(hWnd, evExit);
                    break;
                case IDFILE_OPEN:
                    handlemsg(hWnd, evLoadPlay);
                    break;
                case IDDIR_OPEN:
                {
                    static char path[MAX_PATH];
                    BROWSEINFO bi;
                    LPITEMIDLIST pidl;
                    memset(&bi, 0, sizeof(BROWSEINFO));
                    bi.lpszTitle = "Choose a Directory...";
                    pidl = SHBrowseForFolder(&bi);
                    if (SHGetPathFromIDList(pidl, path))
                    {
                        gui->playlist->clear_playlist(gui->playlist);
                        adddirtoplaylist(gui->playlist, path, TRUE);
                        gui->startplay(gui);
                    }
                    break;
                }
                case ID_SKINBROWSER:
                    handlemsg(hWnd, evSkinBrowser);
                    break;
                case IDURL_OPEN:
                    display_openurlwindow(gui, 0);
                    break;
                case ID_MUTE:
                    mp_input_queue_cmd(mp_input_parse_cmd("mute"));
                    break;
                case IDSUBTITLE_OPEN:
                    display_opensubtitlewindow(gui);
                    break;
                case ID_PTRACK:
                    handlemsg(hWnd, evPrev);
                    break;
                case ID_SEEKB:
                    handlemsg(hWnd, evBackward10sec);
                    break;
                case ID_PLAY:
                    handlemsg(hWnd, evPlaySwitchToPause);
                    break;
                case ID_STOP:
                    handlemsg(hWnd, evStop);
                    break;
                case ID_SEEKF:
                    handlemsg(hWnd, evForward10sec);
                    break;
                case ID_NTRACK:
                    handlemsg(hWnd, evNext);
                    break;
                case ID_SHOWHIDE:
                {
                    if(IsWindowVisible(hWnd)) ShowWindow(hWnd, SW_HIDE);
                    else ShowWindow(hWnd, SW_SHOW);
                    break;
                }
                case ID_PLAYLIST:
                    handlemsg(hWnd, evPlayList);
                    break;
                case ID_PREFS:
                    handlemsg(hWnd, evPreferences);
                    break;
                case ID_CONSOLE:
                    console_toggle();
                    break;
                case ID_ONLINEHELP:
                    ShellExecute(NULL, "open", ONLINE_HELP_URL, NULL, NULL, SW_SHOWNORMAL);
                    break;
            }
            if((IDPLAYDISK <= LOWORD(wParam)) && (LOWORD(wParam) < (IDPLAYDISK + 100)))
            {
                char device[MAX_PATH];
                char searchpath[MAX_PATH];
                char filename[MAX_PATH];
                int len, pos = 0, cdromdrive = 0;
                len = GetLogicalDriveStrings(MAX_PATH, device);
                while(pos < len)
                {
                    if(GetDriveType(device + pos)==DRIVE_CDROM)
                    {
                        if(LOWORD(wParam) - IDPLAYDISK == cdromdrive)
                        {
#ifdef USE_DVDREAD
                            sprintf(searchpath, "%sVIDEO_TS", device + pos);
                            if(GetFileAttributes(searchpath) != INVALID_FILE_ATTRIBUTES)
                            {
                                if (dvd_device) free(dvd_device);
                                dvd_device = strdup(device + pos);
                                dvd_title = dvd_chapter = dvd_angle = 1;
                                handlemsg(hWnd, evPlayDVD);
                            }
#endif
#ifdef HAVE_LIBCDIO
                            sprintf(searchpath, "%sTrack01.cda", device + pos);
                            if(GetFileAttributes(searchpath) != INVALID_FILE_ATTRIBUTES)
                            {
                                if (cdrom_device) free(cdrom_device);
                                cdrom_device = strdup(device + pos);
                                /* mplayer doesn't seem to like the trailing \ after the device name */
                                cdrom_device[2]=0;
                                handlemsg(hWnd, evPlayCD);
                            }
#endif
                            else
                            {
                                HANDLE searchhndl;
                                WIN32_FIND_DATA finddata;
                                sprintf(searchpath, "%smpegav\\*.dat", device + pos);
                                if((searchhndl=FindFirstFile(searchpath, &finddata)) != INVALID_HANDLE_VALUE)
                                {
                                    mp_msg(MSGT_GPLAYER,MSGL_V, "Opening VCD/SVCD\n");
                                    gui->playlist->clear_playlist(gui->playlist);
                                    do
                                    {
                                        sprintf(filename, "%smpegav\\%s", device + pos, finddata.cFileName);
                                        gui->playlist->add_track(gui->playlist, filename, NULL, NULL, 0);
                                    }
                                    while(FindNextFile(searchhndl, &finddata));
                                    FindClose(searchhndl);
                                }
                                gui->startplay(gui);
                            }
                        }
                        cdromdrive++;
                    }
                    pos += strlen(device + pos) + 1;
                }
            }
            break;
        }
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            RECT rd;
            HDC hdc = BeginPaint(hWnd, &ps);
            HDC hMemDC = CreateCompatibleDC(hdc);
            int width, height;
            GetClientRect(hWnd, &rd);
            width = rd.right - rd.left;
            height = rd.bottom - rd.top;
            SelectObject(hMemDC, get_bitmap(hWnd));
            BitBlt(hdc, 0, 0, width, height, hMemDC, 0, 0, SRCCOPY);
            DeleteDC(hMemDC);
            EndPaint(hWnd, &ps);
            return 0;
        }
        return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

inline void startplay(gui_t *gui)
{
    handlemsg(gui->mainwindow, evDropFile);
}

/* returns the bits per pixel of the desktop */
/* the format is always in BGR byte order */
static int GetDesktopBitsPerPixel(void)
{
    HWND desktop=GetDesktopWindow();
    HDC dc=GetDC(desktop);
    int bpp=GetDeviceCaps(dc, BITSPIXEL);
    ReleaseDC(desktop, dc);
    return bpp;
}

/* unloads a skin and destroys its windows */
extern int destroy_window(gui_t *gui)
{
    RECT rd;
    unsigned int i;

    /* Save position: MSDN says don't pass workspace coordinates
     * to CreateWindow() or SetWindowPos(), as both of which expect
     * screen coordinates; resulting in the window appearing in the
     * wrong location.
     * -Erik
     */

    /* main window position */
    if(IsIconic(gui->mainwindow))
        ShowWindow(gui->mainwindow, SW_SHOWNORMAL);
    GetWindowRect(gui->mainwindow, &rd);
    gui_main_pos_x = rd.left;
    gui_main_pos_y = rd.top;

    /* sub window position */
    if(IsIconic(gui->subwindow))
        ShowWindow(gui->subwindow, SW_SHOWNORMAL);
    GetWindowRect(gui->subwindow, &rd);
    gui_sub_pos_x = rd.left;
    gui_sub_pos_y = rd.top;

    for(i=0; i<gui->window_priv_count; i++)
    {
        if(gui->window_priv[i]->bitmap)
            DeleteObject(gui->window_priv[i]->bitmap);
        free(gui->window_priv[i]);
    }
    free(gui->window_priv);
    gui->window_priv = NULL;
    gui->window_priv_count = 0;

    /* destroy the main window */
    if(gui->mainwindow)
        DestroyWindow(gui->mainwindow);
    gui->mainwindow = NULL;

    /* destroy the sub window */
    if(gui->subwindow)
        DestroyWindow(gui->subwindow);
    gui->subwindow = NULL;

    UnregisterClass(gui->classname, 0);
    DestroyIcon(gui->icon);

    gui->skin->freeskin(gui->skin);
    gui->skin = NULL;
    return 0;
}

static void create_menu(gui_t *gui)
{
    gui->diskmenu = CreatePopupMenu();
    gui->menu=CreatePopupMenu();
    gui->trayplaymenu = CreatePopupMenu();
    AppendMenu(gui->menu, MF_STRING | MF_POPUP, (UINT) gui->trayplaymenu, "Open...");
    AppendMenu(gui->trayplaymenu, MF_STRING, IDFILE_OPEN, "File...");
    AppendMenu(gui->trayplaymenu, MF_STRING, IDURL_OPEN, "Url...");
    AppendMenu(gui->trayplaymenu, MF_STRING, IDDIR_OPEN, "Directory...");
    AppendMenu(gui->menu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->menu, MF_STRING | MF_POPUP, (UINT) gui->diskmenu, "Play &CD/DVD/VCD/SVCD");
    AppendMenu(gui->menu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->menu, MF_STRING, IDSUBTITLE_OPEN, "Open Subtitle");
    AppendMenu(gui->menu, MF_STRING, ID_SKINBROWSER, "Skin Browser");
    AppendMenu(gui->menu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->menu, MF_STRING, ID_PREFS, "Preferences");
    AppendMenu(gui->menu, MF_STRING, ID_CONSOLE, "Debug Console");
    AppendMenu(gui->menu, MF_STRING, ID_ONLINEHELP, "Online Help");
    AppendMenu(gui->menu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->menu, MF_STRING, IDEXIT, "&Exit");
}

static void create_traymenu(gui_t *gui)
{
    gui->traymenu = CreatePopupMenu();
    gui->trayplaybackmenu = CreatePopupMenu();
    AppendMenu(gui->traymenu, MF_STRING | MF_POPUP, (UINT) gui->trayplaymenu, "Open...");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING | MF_POPUP, (UINT) gui->trayplaybackmenu, "Playback");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_SEEKB, "Seek Backwards");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_PTRACK, "Previous Track");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_PLAY, "Play/Pause");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_STOP, "Stop");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_NTRACK, "Next Track");
    AppendMenu(gui->trayplaybackmenu, MF_STRING, ID_SEEKF, "Seek Forwards");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING, ID_MUTE, "Toggle Mute");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING, IDSUBTITLE_OPEN, "Open Subtitle");
    AppendMenu(gui->traymenu, MF_STRING, ID_PLAYLIST, "Playlist");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING, ID_SHOWHIDE, "Show/Hide");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING, ID_PREFS, "Preferences");
    AppendMenu(gui->traymenu, MF_STRING, ID_CONSOLE, "Debug Console");
    AppendMenu(gui->traymenu, MF_STRING, ID_ONLINEHELP, "Online Help");
    AppendMenu(gui->traymenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->traymenu, MF_STRING, IDEXIT, "&Exit");
}

static void create_submenu(gui_t *gui)
{
    gui->submenu = CreatePopupMenu();
    gui->dvdmenu = CreatePopupMenu();
    gui->aspectmenu = CreatePopupMenu();
    gui->subtitlemenu = CreatePopupMenu();
    AppendMenu(gui->submenu, MF_STRING | MF_POPUP, (UINT) gui->trayplaymenu, "Open...");
    AppendMenu(gui->submenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->submenu, MF_STRING, ID_SEEKB, "Seek Backwards");
    AppendMenu(gui->submenu, MF_STRING, ID_PTRACK, "Previous Track");
    AppendMenu(gui->submenu, MF_STRING, ID_PLAY, "Play/Pause");
    AppendMenu(gui->submenu, MF_STRING, ID_STOP, "Stop");
    AppendMenu(gui->submenu, MF_STRING, ID_NTRACK, "Next Track");
    AppendMenu(gui->submenu, MF_STRING, ID_SEEKF, "Seek Forwards");
    AppendMenu(gui->submenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->submenu, MF_STRING, ID_FULLSCREEN, "Toggle Fullscreen");
    AppendMenu(gui->submenu, MF_STRING, ID_MUTE, "Toggle Mute");
    AppendMenu(gui->submenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->submenu, MF_STRING | MF_POPUP, (UINT) gui->aspectmenu, "Aspect Ratio");
    AppendMenu(gui->submenu, MF_STRING | MF_POPUP, (UINT) gui->subtitlemenu, "Subtitle Options");
    AppendMenu(gui->submenu, MF_STRING | MF_POPUP, (UINT) gui->dvdmenu, "DVD Options");
#ifdef USE_DVDREAD
    AppendMenu(gui->dvdmenu, MF_STRING | MF_GRAYED, ID_CHAPTERSEL, "Select Title/Chapter...");
#endif
    AppendMenu(gui->subtitlemenu, MF_STRING, IDSUB_TOGGLE, "Subtitle Visibility On/Off");
    AppendMenu(gui->subtitlemenu, MF_STRING, IDSUB_CYCLE, "Cycle Subtitle Languages");
    AppendMenu(gui->aspectmenu, MF_STRING, ID_ASPECT1, "Set 16:9");
    AppendMenu(gui->aspectmenu, MF_STRING, ID_ASPECT2, "Set 4:3");
    AppendMenu(gui->aspectmenu, MF_STRING, ID_ASPECT3, "Set 2.35");
    AppendMenu(gui->aspectmenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->aspectmenu, MF_STRING, ID_ASPECT4, "Original Aspect");
    AppendMenu(gui->submenu, MF_SEPARATOR, 0, 0);
    AppendMenu(gui->submenu, MF_STRING, IDEXIT, "&Exit");
}

static void maketransparent(HWND hwnd, COLORREF crTransparent)
{
    HDC mdc = GetDC(hwnd);
    RECT rd;
    HRGN crRgnres, crRgn, crRgnTmp;
    int iX = 0, iY = 0, iLeftX = 0;
    int width, height;
    GetWindowRect(hwnd, &rd);
    width = rd.right - rd.left;
    height = rd.bottom - rd.top;

    /* create an empty region */
    crRgn = CreateRectRgn(0, 0, 0, 0);

    /* Create a region from a bitmap with transparency colour of Purple */
    for (iY = -1; iY < height; iY++)
    {
        do
        {
            /* skip over transparent pixels at start of lines */
            while (iX <= width && GetPixel(mdc,iX, iY) == crTransparent) iX++;

            /* remember this pixel */
            iLeftX = iX;

            /* now find first non transparent pixel */
            while (iX <= width && GetPixel(mdc,iX, iY) != crTransparent) ++iX;

            /* create a temp region on this info */
            crRgnTmp = CreateRectRgn(iLeftX, iY, iX, iY+1);

            /* combine into main region */
            crRgnres = crRgn;
            CombineRgn(crRgnres, crRgn, crRgnTmp, RGN_OR);
            crRgn = crRgnres;

            /* delete the temp region for next pass (otherwise you'll get an ASSERT) */
            DeleteObject(crRgnTmp);
        } while (iX < width);
        iX = 0;
    }
    SetWindowRgn(hwnd, crRgn, TRUE);
    DeleteObject(crRgn);
    ReleaseDC(hwnd,mdc);
}

static int window_render(gui_t *gui, HWND hWnd, HDC hdc, window_priv_t *priv, window *desc, BITMAPINFO binfo)
{
    int i;
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD) gui);
    (gui->window_priv_count)++;
    gui->window_priv = realloc(gui->window_priv, sizeof(window_priv_t *) * gui->window_priv_count);
    priv = gui->window_priv[gui->window_priv_count - 1] = calloc(1, sizeof(window_priv_t));
    priv->hwnd = hWnd;
    priv->type = desc->type;
    priv->background = desc->base->bitmap[0];
    memcpy(&priv->img, desc->base->bitmap[0], sizeof(image));
    hdc = GetDC(hWnd);
    binfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    binfo.bmiHeader.biWidth = priv->img.width;
    binfo.bmiHeader.biHeight = -priv->img.height;
    binfo.bmiHeader.biPlanes = 1;
    binfo.bmiHeader.biSizeImage = priv->img.width * priv->img.height * (gui->screenbpp / 8);
    binfo.bmiHeader.biXPelsPerMeter = 0;
    binfo.bmiHeader.biYPelsPerMeter = 0;
    binfo.bmiHeader.biClrUsed = 0;
    binfo.bmiHeader.biClrImportant = 0;
    binfo.bmiHeader.biBitCount = gui->screenbpp;
    binfo.bmiHeader.biCompression = BI_RGB;
    priv->bitmap = CreateDIBSection(hdc, &binfo, DIB_RGB_COLORS, (void **) &priv->img.data, NULL, 0);
    if(!priv->bitmap)
    {
        mp_msg(MSGT_GPLAYER, MSGL_FATAL, "[GUI] unable to create bitmap for skinned window\n");
        return 0;
    }
    memcpy(priv->img.data, desc->base->bitmap[0]->data, binfo.bmiHeader.biSizeImage);
    ReleaseDC(hWnd,hdc);

    for (i=0; i<gui->skin->widgetcount; i++)
        if(gui->skin->widgets[i]->window == desc->type)
            renderwidget(gui->skin, &priv->img, gui->skin->widgets[i], 1);

    return 0;
}

/* creates the sub (AKA video) window,*/
extern int create_subwindow(gui_t *gui, char *skindir)
{
    HINSTANCE instance = GetModuleHandle(NULL);
    WNDCLASS wc;
    RECT rect;
    HWND hWnd;
    DWORD style = 0;
    HDC hdc = NULL;
    BITMAPINFO binfo;
    window_priv_t *priv = NULL;
    window *desc = NULL;
    int i, x = -1, y = -1;
    vo_colorkey = 0xff00ff;

    for (i=0; i<gui->skin->windowcount; i++)
        if(gui->skin->windows[i]->type == wiSub)
            desc = gui->skin->windows[i];

    if(!desc)
    {
        mp_msg(MSGT_GPLAYER, MSGL_FATAL, "[GUI] Invalid skin description\n");
        return 1;
    }

    windowcolor = vo_colorkey;
    colorbrush = CreateSolidBrush(windowcolor);
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    wc.lpfnWndProc = SubProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = gui->icon;
    wc.hbrBackground = NULL; //WM_PAINT will handle background color switching;
    wc.lpszClassName = "MPlayer Sub for Windows";
    wc.lpszMenuName = NULL;
    RegisterClass(&wc);

    /* create the sub window menu */
    create_submenu(gui);

    rect.top = rect.left = 100;
    rect.bottom = rect.top+desc->base->bitmap[0]->height;
    rect.right = rect.left+desc->base->bitmap[0]->width;

    /* our window aspect */
    sub_aspect = (float)(rect.right-rect.left)/(rect.bottom-rect.top);

    style = fullscreen?WS_VISIBLE | WS_POPUP:WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_MINIMIZEBOX;
    AdjustWindowRect(&rect, style, 0);

    if (gui_sub_pos_x >= 0)
        x = gui_sub_pos_x;
    if (gui_sub_pos_y >= 0)
        y = gui_sub_pos_y;

    /* out of bounds check */
    if (x <= -1 || (x+(rect.right-rect.left) > GetSystemMetrics(SM_CXSCREEN)))
        x = CW_USEDEFAULT;
    if (y <= -1 || (y+(rect.bottom-rect.top) > GetSystemMetrics(SM_CYSCREEN)))
        y = x;

    hWnd = CreateWindowEx(0, "MPlayer Sub for Windows", "MPlayer for Windows", style,
                          x, y, rect.right-rect.left, rect.bottom-rect.top,
                          gui->subwindow, NULL, instance, NULL);

    /* load all the window images */
    window_render(gui, hWnd, hdc, priv, desc, binfo);

    /* enable drag and drop support */
    DragAcceptFiles(hWnd, TRUE);

    gui->subwindow = hWnd;
    if(sub_window)
        WinID = gui->subwindow;
    ShowWindow(gui->subwindow, SW_SHOW);
    UpdateWindow(gui->subwindow);
    return 0;
}

/* loads/updates a skin and creates windows for it */
extern int create_window(gui_t *gui, char *skindir)
{
    HINSTANCE instance = GetModuleHandle(NULL);
    WNDCLASS wc;
    RECT rect;
    DWORD style = 0;
    HWND hwnd;
    HDC hdc = NULL;
    BITMAPINFO binfo;
    window_priv_t *priv = NULL;
    window *desc = NULL;
    char dir[MAX_PATH];
    unsigned int i;
    int x = -1, y = -1;

    /* destroy the current main window */
    if(gui->skin) destroy_window(gui);

    /* get screenproperties */
    gui->screenbpp = GetDesktopBitsPerPixel();
    gui->screenw = GetSystemMetrics(SM_CXSCREEN);
    gui->screenh = GetSystemMetrics(SM_CYSCREEN);

    /* load the new skin */
    gui->skin = loadskin(skindir, gui->screenbpp);
    if(!gui->skin)
    {
        mp_msg(MSGT_GPLAYER, MSGL_FATAL, "[GUI] fatal error during skinload\n");
        /* Set default Skin */
        if (skinName) free(skinName);
        skinName = strdup("Blue");
        /* then force write conf */
        cfg_write();
        return 1;
    }

    /* find the description of the mainwindow */
    for (i=0; i<gui->skin->windowcount; i++)
        if(gui->skin->windows[i]->type == wiMain)
            desc = gui->skin->windows[i];

    if(!desc)
    {
        mp_msg(MSGT_GPLAYER, MSGL_FATAL, "[GUI] Invalid skin description\n");
        return 1;
    }

    /* load the icon from the executable */
    GetModuleFileName(NULL, dir, MAX_PATH);
    gui->icon = ExtractIcon(instance, dir, 0);

    /* create the window class */
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = EventProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = gui->icon;
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszClassName = gui->classname = "MPlayer GUI for Windows";
    wc.lpszMenuName = NULL;
    RegisterClass(&wc);

    /* create a context menu */
    create_menu(gui);
    /* create the systray menu */
    create_traymenu(gui);

    /* create the mainwindow */
    /* TODO implement aligning as described in skin.html */
    rect.top = rect.left = 100;
    rect.bottom = rect.top+desc->base->bitmap[0]->height;
    rect.right = rect.left+desc->base->bitmap[0]->width;
    if(desc->decoration) style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
    else style = WS_POPUP | WS_SYSMENU;

    AdjustWindowRect(&rect, style, 0);

    /* Check if out of screen */
    if (gui_main_pos_x >= 0)
        x = gui_main_pos_x;
    if (gui_main_pos_y >= 0)
        y = gui_main_pos_y;

    if (x <= -1 || (x+(rect.right-rect.left) > GetSystemMetrics(SM_CXFULLSCREEN)))
    {
        x = (GetSystemMetrics(SM_CXSCREEN) / 2) - ((rect.right-rect.left) / 2);
        gui_main_pos_x = x;
    }
    if (y <= -1 || (y+(rect.bottom-rect.top) > GetSystemMetrics(SM_CYFULLSCREEN)))
    {
        y = ((GetSystemMetrics(SM_CYSCREEN)-40) - (rect.bottom-rect.top));
        gui_main_pos_y = y;
    }

    hwnd = CreateWindowEx(0, gui->classname, "MPlayer for Windows", style,
                          x, y, rect.right-rect.left, rect.bottom-rect.top,
                          gui->mainwindow, NULL, instance, NULL);

    /* set the systray icon properties */
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hwnd;
    nid.uID = 1;
    nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    nid.uCallbackMessage = WM_SYSTRAY;
    nid.hIcon = gui->icon;
    strcpy(nid.szTip, "MPlayer for Windows");

    /* register the systray icon */
    Shell_NotifyIcon(NIM_ADD, &nid);

    /* load all the window images */
    window_render(gui, hwnd, hdc, priv, desc, binfo);

    /* enable drag and drop support */
    DragAcceptFiles(hwnd, TRUE);

    updatedisplay(gui, hwnd);
    gui->mainwindow = hwnd;

    /* display */
    ShowWindow(gui->mainwindow, SW_SHOW);
    UpdateWindow(gui->mainwindow);
    maketransparent(gui->mainwindow, RGB(255, 0, 255));
    return 0;
}

gui_t *create_gui(char *skindir, char *skinName, void (*playercontrol)(int event))
{
    gui_t *gui = calloc(1, sizeof(gui_t));
    char temp[MAX_PATH];
    HWND runningmplayer = FindWindow("MPlayer GUI for Windows", "MPlayer for Windows");

    if(runningmplayer)
    {
        free(gui);
        return NULL;
    }

    gui->startplay = startplay;
    gui->playercontrol = playercontrol;
    gui->uninit = uninit;
    gui->updatedisplay = updatedisplay;

    /* create playlist */
    gui->playlist = create_playlist();

    if(!skinName) skinName = strdup("Blue");
    sprintf(temp, "%s\\%s", skindir, skinName);
    if(create_window(gui, temp)) return NULL;
    if(create_subwindow(gui, temp)) return NULL;
    if(console) console_toggle();
    return gui;
}