Skip to content

Commit

Permalink
osdep/file_dialog-external: add implementation for kdialog and zenity
Browse files Browse the repository at this point in the history
  • Loading branch information
kasper93 committed Feb 10, 2025
1 parent 2a60cd6 commit 589654d
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 28 deletions.
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ if not posix and not features['win32-desktop']
endif

if not win32 and not darwin
sources += files('osdep/file_dialog-dummy.c')
sources += files('osdep/file_dialog-external.c')
endif

# media controls
Expand Down
27 changes: 0 additions & 27 deletions osdep/file_dialog-dummy.c

This file was deleted.

166 changes: 166 additions & 0 deletions osdep/file_dialog-external.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* 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 "file_dialog.h"

#include <player/core.h>

#include "subprocess.h"

#define MAX_ARGS 32

struct subprocess_fd_ctx {
struct mp_log *log;
void* talloc_ctx;
int fd;
bstr output;
};

static void subprocess_read(void *p, char *data, size_t size)
{
struct subprocess_fd_ctx *ctx = p;
if (ctx->fd == STDOUT_FILENO) {
bstr_xappend(ctx->talloc_ctx, &ctx->output, (bstr){data, size});
ctx->output = bstr_strip_linebreaks(ctx->output);
} else {
mp_msg(ctx->log, MSGL_ERR, "%.*s", (int)size, data);
}
}

static void kdialog(void *talloc_ctx, const char *args[MAX_ARGS],
const mp_file_dialog_params *params)
{
int i = 0;

args[i++] = "kdialog";

if (params->flags & MP_FILE_DIALOG_SAVE) {
args[i++] = "--getsavefilename";
} else if (params->flags & MP_FILE_DIALOG_DIRECTORY) {
args[i++] = "--getexistingdirectory";
} else {
args[i++] = "--getopenfilename";
if (params->flags & MP_FILE_DIALOG_MULTIPLE)
args[i++] = "--multiple";
}

args[i++] = params->initial_dir ? params->initial_dir : ".";

if (params->filters) {
char *filter = talloc_strdup(talloc_ctx, "All Files (*)");
for (const mp_file_dialog_filters *f = params->filters; f->name; f++) {
filter = talloc_asprintf_append(filter, "|%s (", f->name);
for (char **ext = f->extensions; *ext; ext++)
filter = talloc_asprintf_append(filter, ext[1] ? "*.%s " : "*.%s)", *ext);
}
args[i++] = filter;
assert(i < MAX_ARGS - 1);
}

args[i++] = NULL;
}

static void zenity(void *talloc_ctx, const char *args[MAX_ARGS],
const mp_file_dialog_params *params)
{
int i = 0;

args[i++] = "zenity";
args[i++] = "--file-selection";

if (params->flags & MP_FILE_DIALOG_DIRECTORY) {
args[i++] = "--directory";
} else if (params->flags & MP_FILE_DIALOG_SAVE) {
args[i++] = "--save";
} else if (params->flags & MP_FILE_DIALOG_MULTIPLE) {
args[i++] = "--multiple";
args[i++] = "--separator=':'";
}

if (params->title) {
args[i++] = "--title";
args[i++] = params->title;
}

if (params->filters) {
args[i++] = "--file-filter";
args[i++] = talloc_strdup(talloc_ctx, "All Files | *");
for (const mp_file_dialog_filters *f = params->filters; f->name; f++) {
char *filter = talloc_asprintf(talloc_ctx, "%s |", f->name);
for (char **ext = f->extensions; *ext; ext++)
filter = talloc_asprintf_append(filter, " *.%s", *ext);
assert(i < MAX_ARGS - 2);
args[i++] = "--file-filter";
args[i++] = filter;
}
}

args[i++] = NULL;
}


typedef void (*dialog_func_t)(void *talloc_ctx, const char *args[MAX_ARGS],
const mp_file_dialog_params *params);

const dialog_func_t dialogs[] = {
kdialog,
zenity,
NULL,
};

char *mp_file_dialog_get_files(void *talloc_ctx, struct MPContext *mpctx,
const mp_file_dialog_params *params)
{
void *tmp = talloc_new(NULL);
const char *args[MAX_ARGS] = {0};
struct mp_subprocess_opts opts = {
.args = (char **)args,
};
struct mp_log *log = mp_log_new(tmp, mpctx->log, "file_dialog");
struct subprocess_fd_ctx ctx[2];
for (int fd = 1; fd < 3; fd++) {
ctx[opts.num_fds] = (struct subprocess_fd_ctx) {
.log = log,
.talloc_ctx = tmp,
.fd = fd,
};
opts.fds[opts.num_fds] = (struct mp_subprocess_fd) {
.fd = fd,
.src_fd = -1,
.on_read = subprocess_read,
.on_read_ctx = &ctx[opts.num_fds],
};
opts.num_fds++;
}

struct mp_subprocess_result res ;

for (int i = 0; dialogs[i]; i++) {
dialogs[i](tmp, (const char **)opts.args, params);
opts.exe = opts.args[0];
mp_subprocess(log, &opts, &res);
if (res.error == MP_SUBPROCESS_OK)
break;
}

char *ret = NULL;
if (res.error == MP_SUBPROCESS_OK && res.exit_status == 0)
ret = bstrdup0(talloc_ctx, ctx[0].output);

talloc_free(tmp);
return ret;
}

0 comments on commit 589654d

Please sign in to comment.