0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00
mpv/video/out/win32/droptarget.c
NRK d05ef7fdc4 various: sort some standard headers
since i was going to fix the include order of stdatomic, might as well
sort the surrouding includes in accordance with the project's coding
style.

some headers can sometime require specific include order. standard
library headers usually don't. but mpv might "hack into" the standard
headers (e.g pthreads) so that complicates things a bit more.

hopefully nothing breaks. if it does, the style guide is to blame.
2023-10-20 21:31:09 +02:00

228 lines
6.6 KiB
C

/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdatomic.h>
#include <windows.h>
#include <ole2.h>
#include <shobjidl.h>
#include "common/msg.h"
#include "common/common.h"
#include "input/input.h"
#include "input/event.h"
#include "osdep/io.h"
#include "osdep/windows_utils.h"
#include "mpv_talloc.h"
#include "droptarget.h"
struct droptarget {
IDropTarget iface;
atomic_int ref_cnt;
struct mp_log *log;
struct input_ctx *input_ctx;
struct mp_vo_opts *opts;
DWORD last_effect;
IDataObject *data_obj;
};
static FORMATETC fmtetc_file = {
.cfFormat = CF_HDROP,
.dwAspect = DVASPECT_CONTENT,
.lindex = -1,
.tymed = TYMED_HGLOBAL,
};
static FORMATETC fmtetc_url = {
.dwAspect = DVASPECT_CONTENT,
.lindex = -1,
.tymed = TYMED_HGLOBAL,
};
static void DropTarget_Destroy(struct droptarget *t)
{
SAFE_RELEASE(t->data_obj);
talloc_free(t);
}
static STDMETHODIMP DropTarget_QueryInterface(IDropTarget *self, REFIID riid,
void **ppvObject)
{
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropTarget)) {
*ppvObject = self;
IDropTarget_AddRef(self);
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
static STDMETHODIMP_(ULONG) DropTarget_AddRef(IDropTarget *self)
{
struct droptarget *t = (struct droptarget *)self;
return atomic_fetch_add(&t->ref_cnt, 1) + 1;
}
static STDMETHODIMP_(ULONG) DropTarget_Release(IDropTarget *self)
{
struct droptarget *t = (struct droptarget *)self;
ULONG ref_cnt = atomic_fetch_add(&t->ref_cnt, -1) - 1;
if (ref_cnt == 0)
DropTarget_Destroy(t);
return ref_cnt;
}
static STDMETHODIMP DropTarget_DragEnter(IDropTarget *self,
IDataObject *pDataObj,
DWORD grfKeyState, POINTL pt,
DWORD *pdwEffect)
{
struct droptarget *t = (struct droptarget *)self;
IDataObject_AddRef(pDataObj);
if (FAILED(IDataObject_QueryGetData(pDataObj, &fmtetc_file)) &&
FAILED(IDataObject_QueryGetData(pDataObj, &fmtetc_url)))
{
*pdwEffect = DROPEFFECT_NONE;
}
SAFE_RELEASE(t->data_obj);
t->data_obj = pDataObj;
t->last_effect = *pdwEffect;
return S_OK;
}
static STDMETHODIMP DropTarget_DragOver(IDropTarget *self, DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
struct droptarget *t = (struct droptarget *)self;
*pdwEffect = t->last_effect;
return S_OK;
}
static STDMETHODIMP DropTarget_DragLeave(IDropTarget *self)
{
struct droptarget *t = (struct droptarget *)self;
SAFE_RELEASE(t->data_obj);
return S_OK;
}
static STDMETHODIMP DropTarget_Drop(IDropTarget *self, IDataObject *pDataObj,
DWORD grfKeyState, POINTL pt,
DWORD *pdwEffect)
{
struct droptarget *t = (struct droptarget *)self;
enum mp_dnd_action action;
if (t->opts->drag_and_drop >= 0) {
action = t->opts->drag_and_drop;
} else {
action = (grfKeyState & MK_SHIFT) ? DND_APPEND : DND_REPLACE;
}
SAFE_RELEASE(t->data_obj);
STGMEDIUM medium;
if (t->opts->drag_and_drop == -2) {
t->last_effect = DROPEFFECT_NONE;
} else if (SUCCEEDED(IDataObject_GetData(pDataObj, &fmtetc_file, &medium))) {
if (GlobalLock(medium.hGlobal)) {
HDROP drop = medium.hGlobal;
UINT files_num = DragQueryFileW(drop, 0xFFFFFFFF, NULL, 0);
char **files = talloc_zero_array(NULL, char*, files_num);
UINT recvd_files = 0;
for (UINT i = 0; i < files_num; i++) {
UINT len = DragQueryFileW(drop, i, NULL, 0);
wchar_t *buf = talloc_array(NULL, wchar_t, len + 1);
if (DragQueryFileW(drop, i, buf, len + 1) == len) {
char *fname = mp_to_utf8(files, buf);
files[recvd_files++] = fname;
MP_VERBOSE(t, "received dropped file: %s\n", fname);
} else {
MP_ERR(t, "error getting dropped file name\n");
}
talloc_free(buf);
}
GlobalUnlock(medium.hGlobal);
mp_event_drop_files(t->input_ctx, recvd_files, files, action);
talloc_free(files);
}
ReleaseStgMedium(&medium);
} else if (SUCCEEDED(IDataObject_GetData(pDataObj, &fmtetc_url, &medium))) {
wchar_t *wurl = GlobalLock(medium.hGlobal);
if (wurl) {
char *url = mp_to_utf8(NULL, wurl);
if (mp_event_drop_mime_data(t->input_ctx, "text/uri-list",
bstr0(url), action) > 0)
{
MP_VERBOSE(t, "received dropped URL: %s\n", url);
} else {
MP_ERR(t, "error getting dropped URL\n");
}
talloc_free(url);
GlobalUnlock(medium.hGlobal);
}
ReleaseStgMedium(&medium);
} else {
t->last_effect = DROPEFFECT_NONE;
}
*pdwEffect = t->last_effect;
return S_OK;
}
static IDropTargetVtbl idroptarget_vtbl = {
.QueryInterface = DropTarget_QueryInterface,
.AddRef = DropTarget_AddRef,
.Release = DropTarget_Release,
.DragEnter = DropTarget_DragEnter,
.DragOver = DropTarget_DragOver,
.DragLeave = DropTarget_DragLeave,
.Drop = DropTarget_Drop,
};
IDropTarget *mp_w32_droptarget_create(struct mp_log *log,
struct mp_vo_opts *opts,
struct input_ctx *input_ctx)
{
fmtetc_url.cfFormat = RegisterClipboardFormatW(L"UniformResourceLocatorW");
struct droptarget *dt = talloc(NULL, struct droptarget);
dt->iface.lpVtbl = &idroptarget_vtbl;
atomic_store(&dt->ref_cnt, 0);
dt->last_effect = 0;
dt->data_obj = NULL;
dt->log = mp_log_new(dt, log, "droptarget");
dt->opts = opts;
dt->input_ctx = input_ctx;
return &dt->iface;
}