More work on the dnd kitten

This commit is contained in:
Kovid Goyal
2026-04-23 12:04:05 +05:30
parent 04b80e49b0
commit 3cf037d263
4 changed files with 30 additions and 25 deletions

View File

@@ -121,7 +121,7 @@ func uniqify_child_names(names []string, is_case_sensitive_filesystem bool) []st
return names return names
} }
func (d *remote_dir_entry) add_remote_data(data []byte, output_buf []byte, has_more bool, parent *remote_dir_entry, is_case_sensitive_filesystem bool) error { func (d *remote_dir_entry) add_remote_data(data []byte, output_buf []byte, has_more bool, is_case_sensitive_filesystem bool) error {
if len(data) > 0 { if len(data) > 0 {
for chunk, derr := range d.b64_decoder.Decode(data, output_buf) { for chunk, derr := range d.b64_decoder.Decode(data, output_buf) {
if derr != nil { if derr != nil {
@@ -143,7 +143,6 @@ func (d *remote_dir_entry) add_remote_data(data []byte, output_buf []byte, has_m
d.dest.Close() d.dest.Close()
d.dest = nil d.dest = nil
d.base_dir = d.base_dir.unref() d.base_dir = d.base_dir.unref()
parent.num_children_finished++
}() }()
if dest, ok := d.dest.(*bufferWriteCloser); ok { if dest, ok := d.dest.(*bufferWriteCloser); ok {
if d.item_type == 1 { if d.item_type == 1 {
@@ -199,9 +198,9 @@ type drop_status struct {
reading_data bool reading_data bool
is_remote_client bool is_remote_client bool
root_remote_dir *remote_dir_entry root_remote_dir *remote_dir_entry
open_remote_dir *remote_dir_entry open_remote_dir *remote_dir_entry
pending_remote_dirs []*remote_dir_entry current_remote_entry *remote_dir_entry // used for m=1 only
} }
var reset_drop_status = drop_status{cell_x: -1, cell_y: -1} var reset_drop_status = drop_status{cell_x: -1, cell_y: -1}
@@ -357,7 +356,6 @@ func (dnd *dnd) on_drop_move(cell_x, cell_y int, has_more bool, offered_mimes st
return return
} }
var current_remote_entry *remote_dir_entry
var drop_buf []byte var drop_buf []byte
func (dnd *dnd) on_remote_drop_data(cmd DC) (err error) { func (dnd *dnd) on_remote_drop_data(cmd DC) (err error) {
@@ -366,7 +364,7 @@ func (dnd *dnd) on_remote_drop_data(cmd DC) (err error) {
return fmt.Errorf("got a remote data response form the terminal without an open remote dir") return fmt.Errorf("got a remote data response form the terminal without an open remote dir")
} }
if cmd.X == 0 && cmd.Y == 0 && cmd.Yp == 0 { if cmd.X == 0 && cmd.Y == 0 && cmd.Yp == 0 {
if current_remote_entry == nil { if drop_status.current_remote_entry == nil {
return fmt.Errorf("got a remote data response form the terminal without a current remote entry") return fmt.Errorf("got a remote data response form the terminal without a current remote entry")
} }
} else { } else {
@@ -374,27 +372,34 @@ func (dnd *dnd) on_remote_drop_data(cmd DC) (err error) {
if num < 0 || num >= len(drop_status.open_remote_dir.children) { if num < 0 || num >= len(drop_status.open_remote_dir.children) {
return fmt.Errorf("got a remote data response from the terminal for an entry that does not exist") return fmt.Errorf("got a remote data response from the terminal for an entry that does not exist")
} }
current_remote_entry = drop_status.open_remote_dir.children[num] drop_status.current_remote_entry = drop_status.open_remote_dir.children[num]
} }
if current_remote_entry.dest == nil { e := drop_status.current_remote_entry
current_remote_entry.item_type = cmd.Xp if e.dest == nil {
e.item_type = cmd.Xp
switch cmd.Xp { switch cmd.Xp {
case 0: case 0:
f, err := utils.CreateAt(drop_status.open_remote_dir.base_dir.handle, current_remote_entry.name) f, err := utils.CreateAt(e.base_dir.handle, e.name)
if err != nil { if err != nil {
return err return err
} }
current_remote_entry.dest = f e.dest = f
default: default:
current_remote_entry.dest = &bufferWriteCloser{&bytes.Buffer{}} e.dest = &bufferWriteCloser{&bytes.Buffer{}}
} }
} }
if sz := max(4096, len(cmd.Payload)+4); len(drop_buf) < sz { if sz := max(4096, len(cmd.Payload)+4); len(drop_buf) < sz {
drop_buf = make([]byte, sz) drop_buf = make([]byte, sz)
} }
if err = current_remote_entry.add_remote_data(cmd.Payload, drop_buf, cmd.Has_more, drop_status.open_remote_dir, dnd.is_case_sensitive_filesystem); err != nil { if err = e.add_remote_data(cmd.Payload, drop_buf, cmd.Has_more, dnd.is_case_sensitive_filesystem); err != nil {
return err return err
} }
if e.dest == nil { // this entry is finished
drop_status.open_remote_dir.num_children_finished++
if e.item_type != 0 && e.item_type != 1 {
// TODO: request the children
}
}
return nil return nil
} }

View File

@@ -51,20 +51,22 @@ type DC = loop.DndCommand
type dir_handle struct { type dir_handle struct {
handle *os.File handle *os.File
refcnt int32 refcnt atomic.Int32
} }
func new_dir_handle(x *os.File) *dir_handle { func new_dir_handle(x *os.File) *dir_handle {
return &dir_handle{x, 1} ans := dir_handle{x, atomic.Int32{}}
ans.refcnt.Store(1)
return &ans
} }
func (d *dir_handle) newref() *dir_handle { func (d *dir_handle) newref() *dir_handle {
atomic.AddInt32(&d.refcnt, 1) d.refcnt.Add(1)
return d return d
} }
func (d *dir_handle) unref() *dir_handle { func (d *dir_handle) unref() *dir_handle {
if atomic.AddInt32(&d.refcnt, -1) <= 0 { if d.refcnt.Add(-1) <= 0 {
d.handle.Close() d.handle.Close()
d.handle = nil d.handle = nil
} }

View File

@@ -668,7 +668,6 @@ get_nth_file_url(const char *uri_list, size_t uri_list_sz, int n, char **path_ou
p = eol + 1; p = eol + 1;
while (*p == '\r' || *p == '\n') p++; while (*p == '\r' || *p == '\n') p++;
} }
if (!found_line) { *error_out = "ENOENT"; return false; } if (!found_line) { *error_out = "ENOENT"; return false; }
/* Must be a file:// URL */ /* Must be a file:// URL */
@@ -695,10 +694,9 @@ get_nth_file_url(const char *uri_list, size_t uri_list_sz, int n, char **path_ou
char resolved[PATH_MAX]; char resolved[PATH_MAX];
if (!realpath(path, resolved)) { if (!realpath(path, resolved)) {
switch (errno) { switch (errno) {
case ENOENT: case ENOTDIR: *error_out = "ENOENT"; break; case ENOENT: case ENOTDIR: case ELOOP: *error_out = "ENOENT"; break;
case EACCES: case EPERM: *error_out = "EPERM"; break; case EACCES: case EPERM: *error_out = "EPERM"; break;
case ELOOP: *error_out = "ENOENT"; break; default: *error_out = "EINVAL"; break;
default: *error_out = "EINVAL"; break;
} }
return false; return false;
} }
@@ -951,7 +949,7 @@ drop_send_dir_listing(Window *w, const char *path) {
queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, hdr, hdr_sz, NULL, 0, true); queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, hdr, hdr_sz, NULL, 0, true);
} }
/* Handle a t=s request: send the file/directory at URI-list index idx. /* Send the file/directory at URI-list index idx.
* Returns true if completed synchronously, false if async file I/O started. */ * Returns true if completed synchronously, false if async file I/O started. */
static bool static bool
do_drop_request_uri_data(Window *w, int32_t mime_idx, int32_t file_idx) { do_drop_request_uri_data(Window *w, int32_t mime_idx, int32_t file_idx) {

View File

@@ -42,7 +42,7 @@ def create_fs(base):
f.write(b'x' * sz) f.write(b'x' * sz)
os.makedirs(join('d1', 'sd', 'ssd')) os.makedirs(join('d1', 'sd', 'ssd'))
os.mkdir(join('d2')) os.mkdir(join('d2'))
os.symlink('/does-not-exist', join('s1')) # os.symlink('/does-not-exist', join('s1'))
os.symlink('d1', join('sd')) os.symlink('d1', join('sd'))
os.symlink('/', join('sr')) os.symlink('/', join('sr'))
os.symlink('../d1', join('d1', 'sr')) os.symlink('../d1', join('d1', 'sr'))