| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| namespace eval xdnd { |
| variable _dragging 0 |
|
|
| proc initialise { } { |
| |
| ::tkdnd::generic::initialise_platform_to_tkdnd_types [list \ |
| text/plain\;charset=utf-8 DND_Text \ |
| UTF8_STRING DND_Text \ |
| text/plain DND_Text \ |
| STRING DND_Text \ |
| TEXT DND_Text \ |
| COMPOUND_TEXT DND_Text \ |
| text/uri-list DND_Files \ |
| text/html\;charset=utf-8 DND_HTML \ |
| text/html DND_HTML \ |
| application/x-color DND_Color \ |
| ] |
| } |
|
|
| } |
|
|
| |
| |
| |
| proc xdnd::HandleXdndEnter { path drag_source typelist time { data {} } } { |
| variable _pressedkeys |
| variable _actionlist |
| variable _typelist |
| set _pressedkeys 1 |
| set _actionlist { copy move link ask private } |
| set _typelist $typelist |
| |
| ::tkdnd::generic::SetDroppedData $data |
| ::tkdnd::generic::HandleEnter $path $drag_source $typelist $typelist \ |
| $_actionlist $_pressedkeys |
| } |
|
|
| |
| |
| |
| proc xdnd::HandleXdndPosition { drop_target rootX rootY time {drag_source {}} } { |
| variable _pressedkeys |
| variable _typelist |
| variable _last_mouse_root_x; set _last_mouse_root_x $rootX |
| variable _last_mouse_root_y; set _last_mouse_root_y $rootY |
| |
| |
| catch { |
| ::tkdnd::generic::SetDroppedData [GetPositionData $drop_target $_typelist $time] |
| } |
| ::tkdnd::generic::HandlePosition $drop_target $drag_source \ |
| $_pressedkeys $rootX $rootY |
| } |
|
|
| |
| |
| |
| proc xdnd::HandleXdndLeave { } { |
| ::tkdnd::generic::HandleLeave |
| } |
|
|
| |
| |
| |
| proc xdnd::HandleXdndDrop { time } { |
| variable _pressedkeys |
| variable _last_mouse_root_x |
| variable _last_mouse_root_y |
| |
| ::tkdnd::generic::SetDroppedData [GetDroppedData \ |
| [::tkdnd::generic::GetDragSource] [::tkdnd::generic::GetDropTarget] \ |
| [::tkdnd::generic::GetDragSourceCommonTypes] $time] |
| ::tkdnd::generic::HandleDrop {} {} $_pressedkeys \ |
| $_last_mouse_root_x $_last_mouse_root_y $time |
| } |
|
|
| |
| |
| |
| proc xdnd::GetPositionData { drop_target typelist time } { |
| foreach {drop_target common_drag_source_types common_drop_target_types} \ |
| [::tkdnd::generic::FindWindowWithCommonTypes $drop_target $typelist] {break} |
| GetDroppedData [::tkdnd::generic::GetDragSource] $drop_target \ |
| $common_drag_source_types $time |
| } |
|
|
| |
| |
| |
| proc xdnd::GetDroppedData { _drag_source _drop_target _common_drag_source_types time } { |
| if {![llength $_common_drag_source_types]} { |
| error "no common data types between the drag source and drop target widgets" |
| } |
| |
| if {[catch {winfo pathname -displayof $_drop_target $_drag_source} p]} { |
| set _use_tk_selection 0 |
| } else { |
| set _use_tk_selection 1 |
| } |
| foreach type $_common_drag_source_types { |
| |
| |
| if {$_use_tk_selection} { |
| if {![catch { |
| selection get -displayof $_drop_target -selection XdndSelection \ |
| -type $type |
| } result options]} { |
| return [normalise_data $type $result] |
| } |
| } else { |
| |
| |
| |
| |
| if {![catch { |
| _selection_get -displayof $_drop_target -selection XdndSelection \ |
| -type $type -time $time |
| } result options]} { |
| return [normalise_data $type $result] |
| } |
| } |
| } |
| return -options $options $result |
| } |
|
|
| |
| |
| |
| proc xdnd::platform_specific_types { types } { |
| ::tkdnd::generic::platform_specific_types $types |
| } |
|
|
| |
| |
| |
| proc xdnd::platform_specific_type { type } { |
| ::tkdnd::generic::platform_specific_type $type |
| } |
|
|
| |
| |
| |
| proc ::tkdnd::platform_independent_types { types } { |
| ::tkdnd::generic::platform_independent_types $types |
| } |
|
|
| |
| |
| |
| proc xdnd::platform_independent_type { type } { |
| ::tkdnd::generic::platform_independent_type $type |
| } |
|
|
| |
| |
| |
| proc xdnd::normalise_data { type data } { |
| |
| |
| |
| |
| switch -glob $type { |
| STRING - UTF8_STRING - TEXT - COMPOUND_TEXT {return $data} |
| text/html { |
| if {[catch { |
| encoding convertfrom unicode $data |
| } string]} { |
| set string $data |
| } |
| return [string map {\r\n \n} $string] |
| } |
| text/html\;charset=utf-8 - |
| text/plain\;charset=utf-8 - |
| text/plain { |
| if {[catch { |
| encoding convertfrom utf-8 [tkdnd::bytes_to_string $data] |
| } string]} { |
| set string $data |
| } |
| return [string map {\r\n \n} $string] |
| } |
| text/uri-list* { |
| if {[catch { |
| encoding convertfrom utf-8 [tkdnd::bytes_to_string $data] |
| } string]} { |
| set string $data |
| } |
| |
| set string [string trim [string map {\r\n \n} $string]] |
| set files {} |
| foreach quoted_file [split $string] { |
| set file [tkdnd::urn_unquote $quoted_file] |
| switch -glob $file { |
| \#* {} |
| file://* {lappend files [string range $file 7 end]} |
| ftp://* - |
| https://* - |
| http://* {lappend files $quoted_file} |
| default {lappend files $file} |
| } |
| } |
| return $files |
| } |
| application/x-color { |
| return $data |
| } |
| text/x-moz-url - |
| application/q-iconlist - |
| default {return $data} |
| } |
| } |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| proc xdnd::_selection_ownership_lost {} { |
| variable _dragging |
| set _dragging 0 |
| } |
|
|
| |
| |
| |
| proc xdnd::_dodragdrop { source actions types data button } { |
| variable _dragging |
|
|
| |
| |
| if {$_dragging} { |
| |
| error "another drag operation in progress" |
| } |
|
|
| variable _dodragdrop_drag_source $source |
| variable _dodragdrop_drop_target 0 |
| variable _dodragdrop_drop_target_proxy 0 |
| variable _dodragdrop_actions $actions |
| variable _dodragdrop_action_descriptions $actions |
| variable _dodragdrop_actions_len [llength $actions] |
| variable _dodragdrop_types $types |
| variable _dodragdrop_types_len [llength $types] |
| variable _dodragdrop_data $data |
| variable _dodragdrop_transfer_data {} |
| variable _dodragdrop_button $button |
| variable _dodragdrop_time 0 |
| variable _dodragdrop_default_action refuse_drop |
| variable _dodragdrop_waiting_status 0 |
| variable _dodragdrop_drop_target_accepts_drop 0 |
| variable _dodragdrop_drop_target_accepts_action refuse_drop |
| variable _dodragdrop_current_cursor $_dodragdrop_default_action |
| variable _dodragdrop_drop_occured 0 |
| variable _dodragdrop_selection_requestor 0 |
|
|
| |
| |
| |
| |
| if {$_dodragdrop_types_len > 3} { |
| _announce_type_list $_dodragdrop_drag_source $_dodragdrop_types |
| } |
|
|
| |
| |
| |
| |
| _announce_action_list $_dodragdrop_drag_source $_dodragdrop_actions \ |
| $_dodragdrop_action_descriptions |
|
|
| |
| |
| |
| registerSelectionHandler $source $types |
|
|
| |
| |
| |
| selection own -command ::tkdnd::xdnd::_selection_ownership_lost \ |
| -selection XdndSelection $source |
| set _dragging 1 |
|
|
| |
| _grab_pointer $source $_dodragdrop_default_action |
|
|
| |
| |
| |
| |
| _register_generic_event_handler |
|
|
| |
| |
|
|
| tkwait variable ::tkdnd::xdnd::_dragging |
| _SendXdndLeave |
|
|
| set _dragging 0 |
| _ungrab_pointer $source |
| _unregister_generic_event_handler |
| catch {selection clear -selection XdndSelection} |
| unregisterSelectionHandler $source $types |
| return $_dodragdrop_drop_target_accepts_action |
| } |
|
|
| |
| |
| |
| proc xdnd::_process_drag_events {event} { |
| |
| |
| |
| variable _dragging |
| if {!$_dragging} {return 0} |
| |
|
|
| variable _dodragdrop_time |
| set time [dict get $event time] |
| set type [dict get $event type] |
| if {$time < $_dodragdrop_time && ![string equal $type SelectionRequest]} { |
| return 0 |
| } |
| set _dodragdrop_time $time |
|
|
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target |
| variable _dodragdrop_drop_target_proxy |
| variable _dodragdrop_default_action |
| switch $type { |
| MotionNotify { |
| set rootx [dict get $event x_root] |
| set rooty [dict get $event y_root] |
| set window [_find_drop_target_window $_dodragdrop_drag_source \ |
| $rootx $rooty] |
| if {[string length $window]} { |
| |
| set _dodragdrop_default_action [_default_action $event] |
| |
| |
| |
| if {$_dodragdrop_drop_target != $window} { |
| |
| _SendXdndLeave |
| |
| |
| set proxy [_find_drop_target_proxy $_dodragdrop_drag_source $window] |
| |
| _SendXdndEnter $window $proxy |
| |
| _SendXdndPosition $rootx $rooty $_dodragdrop_default_action |
| } else { |
| |
| _SendXdndPosition $rootx $rooty $_dodragdrop_default_action |
| } |
| } else { |
| |
| _SendXdndLeave |
| } |
| } |
| ButtonPress { |
| } |
| ButtonRelease { |
| variable _dodragdrop_button |
| set button [dict get $event button] |
| if {$button == $_dodragdrop_button} { |
| |
| _SendXdndDrop |
| } |
| return 1 |
| } |
| KeyPress { |
| } |
| KeyRelease { |
| set keysym [dict get $event keysym] |
| switch $keysym { |
| Escape { |
| |
| if {$_dragging} {set _dragging 0} |
| } |
| } |
| } |
| SelectionRequest { |
| variable _dodragdrop_selection_requestor |
| variable _dodragdrop_selection_property |
| variable _dodragdrop_selection_selection |
| variable _dodragdrop_selection_target |
| variable _dodragdrop_selection_time |
| set _dodragdrop_selection_requestor [dict get $event requestor] |
| set _dodragdrop_selection_property [dict get $event property] |
| set _dodragdrop_selection_selection [dict get $event selection] |
| set _dodragdrop_selection_target [dict get $event target] |
| set _dodragdrop_selection_time $time |
| return 0 |
| } |
| default { |
| return 0 |
| } |
| } |
| return 0 |
| } |
|
|
| |
| |
| |
| proc xdnd::_SendXdndEnter {window proxy} { |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target |
| variable _dodragdrop_drop_target_proxy |
| variable _dodragdrop_types |
| variable _dodragdrop_waiting_status |
| variable _dodragdrop_drop_occured |
| if {$_dodragdrop_drop_target > 0} _SendXdndLeave |
| if {$_dodragdrop_drop_occured} return |
| set _dodragdrop_drop_target $window |
| set _dodragdrop_drop_target_proxy $proxy |
| set _dodragdrop_waiting_status 0 |
| if {$_dodragdrop_drop_target < 1} return |
| |
| _send_XdndEnter $_dodragdrop_drag_source $_dodragdrop_drop_target \ |
| $_dodragdrop_drop_target_proxy $_dodragdrop_types |
| } |
|
|
| |
| |
| |
| proc xdnd::_SendXdndPosition {rootx rooty action} { |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target |
| if {$_dodragdrop_drop_target < 1} return |
| variable _dodragdrop_drop_occured |
| if {$_dodragdrop_drop_occured} return |
| variable _dodragdrop_drop_target_proxy |
| variable _dodragdrop_waiting_status |
| |
| variable _dodragdrop_xdnd_position_heartbeat |
| catch {after cancel $_dodragdrop_xdnd_position_heartbeat} |
| set _dodragdrop_xdnd_position_heartbeat [after 200 \ |
| [list ::tkdnd::xdnd::_SendXdndPosition $rootx $rooty $action]] |
| if {$_dodragdrop_waiting_status} {return} |
| |
| _send_XdndPosition $_dodragdrop_drag_source $_dodragdrop_drop_target \ |
| $_dodragdrop_drop_target_proxy $rootx $rooty $action |
| set _dodragdrop_waiting_status 1 |
| } |
|
|
| |
| |
| |
| proc xdnd::_HandleXdndStatus {event} { |
| variable _dodragdrop_drop_target |
| variable _dodragdrop_waiting_status |
|
|
| variable _dodragdrop_drop_target_accepts_drop |
| variable _dodragdrop_drop_target_accepts_action |
| set _dodragdrop_waiting_status 0 |
| foreach key {target accept want_position action x y w h} { |
| set $key [dict get $event $key] |
| } |
| set _dodragdrop_drop_target_accepts_drop $accept |
| set _dodragdrop_drop_target_accepts_action $action |
| if {$_dodragdrop_drop_target < 1} return |
| variable _dodragdrop_drop_occured |
| if {$_dodragdrop_drop_occured} return |
| _update_cursor |
| |
| } |
|
|
| |
| |
| |
| proc xdnd::_HandleXdndFinished {event} { |
| variable _dodragdrop_xdnd_finished_event_after_id |
| catch {after cancel $_dodragdrop_xdnd_finished_event_after_id} |
| set _dodragdrop_xdnd_finished_event_after_id {} |
| variable _dodragdrop_drop_target |
| set _dodragdrop_drop_target 0 |
| variable _dragging |
| if {$_dragging} {set _dragging 0} |
|
|
| variable _dodragdrop_drop_target_accepts_drop |
| variable _dodragdrop_drop_target_accepts_action |
| if {[dict size $event]} { |
| foreach key {target accept action} { |
| set $key [dict get $event $key] |
| } |
| set _dodragdrop_drop_target_accepts_drop $accept |
| set _dodragdrop_drop_target_accepts_action $action |
| } else { |
| set _dodragdrop_drop_target_accepts_drop 0 |
| } |
| if {!$_dodragdrop_drop_target_accepts_drop} { |
| set _dodragdrop_drop_target_accepts_action refuse_drop |
| } |
| |
| } |
|
|
| |
| |
| |
| proc xdnd::_SendXdndLeave {} { |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target |
| if {$_dodragdrop_drop_target < 1} return |
| variable _dodragdrop_drop_target_proxy |
| |
| _send_XdndLeave $_dodragdrop_drag_source $_dodragdrop_drop_target \ |
| $_dodragdrop_drop_target_proxy |
| set _dodragdrop_drop_target 0 |
| variable _dodragdrop_drop_target_accepts_drop |
| variable _dodragdrop_drop_target_accepts_action |
| set _dodragdrop_drop_target_accepts_drop 0 |
| set _dodragdrop_drop_target_accepts_action refuse_drop |
| variable _dodragdrop_drop_occured |
| if {$_dodragdrop_drop_occured} return |
| _update_cursor |
| } |
|
|
| |
| |
| |
| proc xdnd::_SendXdndDrop {} { |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target |
| if {$_dodragdrop_drop_target < 1} { |
| |
| _HandleXdndFinished {} |
| return |
| } |
| variable _dodragdrop_drop_occured |
| if {$_dodragdrop_drop_occured} {return} |
| variable _dodragdrop_drop_target_proxy |
| variable _dodragdrop_drop_target_accepts_drop |
| variable _dodragdrop_drop_target_accepts_action |
|
|
| set _dodragdrop_drop_occured 1 |
| _update_cursor clock |
|
|
| if {!$_dodragdrop_drop_target_accepts_drop} { |
| _SendXdndLeave |
| _HandleXdndFinished {} |
| return |
| } |
| |
| variable _dodragdrop_drop_timestamp |
| set _dodragdrop_drop_timestamp [_send_XdndDrop \ |
| $_dodragdrop_drag_source $_dodragdrop_drop_target \ |
| $_dodragdrop_drop_target_proxy] |
| set _dodragdrop_drop_target 0 |
| |
| |
| variable _dodragdrop_xdnd_finished_event_after_id |
| set _dodragdrop_xdnd_finished_event_after_id \ |
| [after 10000 [list ::tkdnd::xdnd::_HandleXdndFinished {}]] |
| } |
|
|
| |
| |
| |
| proc xdnd::_update_cursor { {cursor {}}} { |
| |
| variable _dodragdrop_current_cursor |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_drop_target_accepts_drop |
| variable _dodragdrop_drop_target_accepts_action |
|
|
| if {![string length $cursor]} { |
| set cursor refuse_drop |
| if {$_dodragdrop_drop_target_accepts_drop} { |
| set cursor $_dodragdrop_drop_target_accepts_action |
| } |
| } |
| if {![string equal $cursor $_dodragdrop_current_cursor]} { |
| _set_pointer_cursor $_dodragdrop_drag_source $cursor |
| set _dodragdrop_current_cursor $cursor |
| } |
| } |
|
|
| |
| |
| |
| proc xdnd::_default_action {event} { |
| variable _dodragdrop_actions |
| variable _dodragdrop_actions_len |
| if {$_dodragdrop_actions_len == 1} {return [lindex $_dodragdrop_actions 0]} |
|
|
| set alt [dict get $event Alt] |
| set shift [dict get $event Shift] |
| set control [dict get $event Control] |
|
|
| if {$shift && $control && [lsearch $_dodragdrop_actions link] != -1} { |
| return link |
| } elseif {$control && [lsearch $_dodragdrop_actions copy] != -1} { |
| return copy |
| } elseif {$shift && [lsearch $_dodragdrop_actions move] != -1} { |
| return move |
| } elseif {$alt && [lsearch $_dodragdrop_actions link] != -1} { |
| return link |
| } |
| return default |
| } |
|
|
| |
| |
| |
| proc xdnd::getFormatForType {type} { |
| switch -glob [string tolower $type] { |
| text/plain\;charset=utf-8 - |
| text/html\;charset=utf-8 - |
| utf8_string {set format UTF8_STRING} |
| text/html - |
| text/plain - |
| string - |
| text - |
| compound_text {set format STRING} |
| text/uri-list* {set format UTF8_STRING} |
| application/x-color {set format $type} |
| default {set format $type} |
| } |
| return $format |
| } |
|
|
| |
| |
| |
| proc xdnd::registerSelectionHandler {source types} { |
| foreach type $types { |
| selection handle -selection XdndSelection \ |
| -type $type \ |
| -format [getFormatForType $type] \ |
| $source [list ::tkdnd::xdnd::_SendData $type] |
| } |
| } |
|
|
| |
| |
| |
| proc xdnd::unregisterSelectionHandler {source types} { |
| foreach type $types { |
| catch { |
| selection handle -selection XdndSelection \ |
| -type $type \ |
| -format [getFormatForType $type] \ |
| $source {} |
| } |
| } |
| } |
|
|
| |
| |
| |
| proc xdnd::_convert_to_unsigned {data format} { |
| switch $format { |
| 8 { set mask 0xff } |
| 16 { set mask 0xffff } |
| 32 { set mask 0xffffff } |
| default {error "unsupported format $format"} |
| } |
| |
| set d [list] |
| foreach num $data { |
| lappend d [expr { $num & $mask }] |
| } |
| return $d |
| } |
|
|
| |
| |
| |
| proc xdnd::_SendData {type offset bytes args} { |
| variable _dodragdrop_drag_source |
| variable _dodragdrop_types |
| variable _dodragdrop_data |
| variable _dodragdrop_transfer_data |
|
|
| |
| |
| |
| set index [lsearch $_dodragdrop_types $type] |
| if {$index < 0} { |
| error "unable to locate data suitable for type \"$type\"" |
| } |
| set typed_data [lindex $_dodragdrop_data $index] |
| set format 8 |
| if {$offset == 0} { |
| |
| switch -glob $type { |
| text/plain* - UTF8_STRING - STRING - TEXT - COMPOUND_TEXT { |
| binary scan [encoding convertto utf-8 $typed_data] \ |
| c* _dodragdrop_transfer_data |
| set _dodragdrop_transfer_data \ |
| [_convert_to_unsigned $_dodragdrop_transfer_data $format] |
| } |
| text/uri-list* { |
| set files [list] |
| foreach file $typed_data { |
| switch -glob $file { |
| *://* {lappend files $file} |
| default {lappend files file://$file} |
| } |
| } |
| binary scan [encoding convertto utf-8 "[join $files \r\n]\r\n"] \ |
| c* _dodragdrop_transfer_data |
| set _dodragdrop_transfer_data \ |
| [_convert_to_unsigned $_dodragdrop_transfer_data $format] |
| } |
| application/x-color { |
| set format 16 |
| |
| |
| |
| switch [llength $typed_data] { |
| 1 { set color [winfo rgb $_dodragdrop_drag_source $typed_data] |
| lappend color 65535 } |
| 3 { set color $typed_data; lappend color 65535 } |
| 4 { set color $typed_data } |
| default {error "unknown color data: \"$typed_data\""} |
| } |
| |
| set _dodragdrop_transfer_data [list] |
| foreach c $color { |
| lappend _dodragdrop_transfer_data [format 0x%04X $c] |
| } |
| } |
| default { |
| set format 32 |
| binary scan $typed_data c* _dodragdrop_transfer_data |
| } |
| } |
| } |
|
|
| |
| |
| |
| set data [lrange $_dodragdrop_transfer_data $offset [expr {$offset+$bytes-1}]] |
| switch $format { |
| 8 { |
| set data [encoding convertfrom utf-8 [binary format c* $data]] |
| } |
| 16 { |
| variable _dodragdrop_selection_requestor |
| if {$_dodragdrop_selection_requestor} { |
| |
| |
| set numItems [llength $data] |
| variable _dodragdrop_selection_property |
| variable _dodragdrop_selection_selection |
| variable _dodragdrop_selection_target |
| variable _dodragdrop_selection_time |
| XChangeProperty $_dodragdrop_drag_source \ |
| $_dodragdrop_selection_requestor \ |
| $_dodragdrop_selection_property \ |
| $_dodragdrop_selection_target \ |
| $format \ |
| $_dodragdrop_selection_time \ |
| $data $numItems |
| return -code break |
| } |
| } |
| 32 { |
| } |
| default { |
| error "unsupported format $format" |
| } |
| } |
| |
| |
| return $data |
| } |
|
|