mirror of
https://github.com/Anjok07/ultimatevocalremovergui.git
synced 2024-12-18 18:35:57 +01:00
884 lines
34 KiB
Tcl
884 lines
34 KiB
Tcl
#
|
|
# tkdnd_unix.tcl --
|
|
#
|
|
# This file implements some utility procedures that are used by the TkDND
|
|
# package.
|
|
#
|
|
# This software is copyrighted by:
|
|
# George Petasis, National Centre for Scientific Research "Demokritos",
|
|
# Aghia Paraskevi, Athens, Greece.
|
|
# e-mail: petasis@iit.demokritos.gr
|
|
#
|
|
# The following terms apply to all files associated
|
|
# with the software unless explicitly disclaimed in individual files.
|
|
#
|
|
# The authors hereby grant permission to use, copy, modify, distribute,
|
|
# and license this software and its documentation for any purpose, provided
|
|
# that existing copyright notices are retained in all copies and that this
|
|
# notice is included verbatim in any distributions. No written agreement,
|
|
# license, or royalty fee is required for any of the authorized uses.
|
|
# Modifications to this software may be copyrighted by their authors
|
|
# and need not follow the licensing terms described here, provided that
|
|
# the new terms are clearly indicated on the first page of each file where
|
|
# they apply.
|
|
#
|
|
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
# MODIFICATIONS.
|
|
#
|
|
|
|
namespace eval xdnd {
|
|
variable _dragging 0
|
|
|
|
proc debug { msg } {
|
|
tkdnd::debug $msg
|
|
};# debug
|
|
|
|
proc initialise { } {
|
|
## Mapping from platform types to TkDND types...
|
|
::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 \
|
|
]
|
|
};# initialise
|
|
|
|
};# namespace xdnd
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::HandleXdndEnter
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::GetPressedKeys { drop_target } {
|
|
#DBG debug "xdnd::GetPressedKeys: $drop_target"
|
|
if {[catch {set dict [_keyboard_get_state $drop_target]}]} {
|
|
return {}
|
|
}
|
|
set pressedkeys {}
|
|
for {set b 1} {$b <= 5} {incr b} {
|
|
if {[dict get $dict $b]} {lappend pressedkeys $b}
|
|
}
|
|
foreach {k l} {Alt alt Shift shift Control ctrl Lock caps_lock
|
|
Mod1 mod1 Mod2 mod2 Mod3 mod3 Mod4 mod4 Mod5 mod5} {
|
|
if {[dict get $dict $k]} {lappend pressedkeys $l}
|
|
}
|
|
#DBG debug "xdnd::GetPressedKeys: $drop_target -> $pressedkeys"
|
|
return $pressedkeys
|
|
};# xdnd::GetPressedKeys
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::HandleXdndEnter
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::HandleXdndEnter { drop_target drag_source typelist time
|
|
{ data {} } } {
|
|
variable _pressedkeys
|
|
variable _actionlist
|
|
variable _typelist
|
|
set _pressedkeys [GetPressedKeys $drop_target]
|
|
set _actionlist { copy move link ask private }
|
|
set _typelist $typelist
|
|
#DBG debug "xdnd::HandleXdndEnter: $time"
|
|
::tkdnd::generic::SetDroppedData $data
|
|
::tkdnd::generic::HandleEnter $drop_target $drag_source $typelist $typelist \
|
|
$_actionlist $_pressedkeys
|
|
};# xdnd::HandleXdndEnter
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::HandleXdndPosition
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::HandleXdndPosition { drop_target rootX rootY time
|
|
{ drag_source {} } { action default } } {
|
|
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
|
|
set _pressedkeys [GetPressedKeys $drop_target]
|
|
#DBG debug "xdnd::HandleXdndPosition: $time"
|
|
## Get the dropped data...
|
|
catch {
|
|
::tkdnd::generic::SetDroppedData [GetPositionData $drop_target $_typelist $time]
|
|
}
|
|
::tkdnd::generic::HandlePosition $drop_target $drag_source \
|
|
$_pressedkeys $rootX $rootY $action
|
|
};# xdnd::HandleXdndPosition
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::HandleXdndLeave
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::HandleXdndLeave { } {
|
|
#DBG debug "xdnd::HandleXdndLeave"
|
|
::tkdnd::generic::HandleLeave
|
|
};# xdnd::HandleXdndLeave
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_HandleXdndDrop
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::HandleXdndDrop { time } {
|
|
variable _pressedkeys
|
|
variable _last_mouse_root_x
|
|
variable _last_mouse_root_y
|
|
set _pressedkeys [GetPressedKeys [::tkdnd::generic::GetDropTarget]]
|
|
#DBG debug "xdnd::HandleXdndDrop: $time"
|
|
## Get the dropped data...
|
|
::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
|
|
};# xdnd::HandleXdndDrop
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::GetPositionData
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
};# xdnd::GetPositionData
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::GetDroppedData
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::GetDroppedData { _drag_source _drop_target _common_drag_source_types time } {
|
|
if {![llength $_common_drag_source_types]} {
|
|
return -code error "no common data types between the drag source and drop target widgets"
|
|
}
|
|
## Is drag source in this application?
|
|
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 {
|
|
#DBG debug "TYPE: $type ($_drop_target)"
|
|
# _get_selection $_drop_target $time $type
|
|
if {$_use_tk_selection} {
|
|
if {![catch {
|
|
selection get -displayof $_drop_target -selection XdndSelection \
|
|
-type $type
|
|
} result options]} {
|
|
return [normalise_data $type $result]
|
|
}
|
|
} else {
|
|
#DBG debug "_selection_get -displayof $_drop_target -selection XdndSelection \
|
|
# -type $type -time $time"
|
|
#after 100 [list focus -force $_drop_target]
|
|
#after 50 [list raise [winfo toplevel $_drop_target]]
|
|
if {![catch {
|
|
_selection_get -displayof $_drop_target -selection XdndSelection \
|
|
-type $type -time $time
|
|
} result options]} {
|
|
return [normalise_data $type $result]
|
|
}
|
|
}
|
|
}
|
|
return -options $options $result
|
|
};# xdnd::GetDroppedData
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::platform_specific_types
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::platform_specific_types { types } {
|
|
::tkdnd::generic::platform_specific_types $types
|
|
}; # xdnd::platform_specific_types
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::platform_specific_type
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::platform_specific_type { type } {
|
|
::tkdnd::generic::platform_specific_type $type
|
|
}; # xdnd::platform_specific_type
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command tkdnd::platform_independent_types
|
|
# ----------------------------------------------------------------------------
|
|
proc ::tkdnd::platform_independent_types { types } {
|
|
::tkdnd::generic::platform_independent_types $types
|
|
}; # tkdnd::platform_independent_types
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::platform_independent_type
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::platform_independent_type { type } {
|
|
::tkdnd::generic::platform_independent_type $type
|
|
}; # xdnd::platform_independent_type
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_normalise_data
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::normalise_data { type data } {
|
|
# Tk knows how to interpret the following types:
|
|
# STRING, TEXT, COMPOUND_TEXT
|
|
# UTF8_STRING
|
|
# Else, it returns a list of 8 or 32 bit numbers...
|
|
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
|
|
}
|
|
## Get rid of \r\n
|
|
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}
|
|
}
|
|
}; # xdnd::normalise_data
|
|
|
|
#############################################################################
|
|
##
|
|
## XDND drag implementation
|
|
##
|
|
#############################################################################
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_selection_ownership_lost
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_selection_ownership_lost {} {
|
|
variable _dragging
|
|
set _dragging 0
|
|
};# _selection_ownership_lost
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_dodragdrop
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_dodragdrop { source actions types data button { cursor_map {} } } {
|
|
variable _dragging
|
|
|
|
#DBG debug "xdnd::_dodragdrop: source: $source, actions: $actions, types: $types,\
|
|
#DBG data: \"$data\", button: $button"
|
|
if {$_dragging} {
|
|
## We are in the middle of another drag operation...
|
|
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
|
|
variable _dodragdrop_cursor_map $cursor_map
|
|
|
|
##
|
|
## If we have more than 3 types, the property XdndTypeList must be set on
|
|
## the drag source widget...
|
|
##
|
|
if {$_dodragdrop_types_len > 3} {
|
|
_announce_type_list $_dodragdrop_drag_source $_dodragdrop_types
|
|
}
|
|
|
|
##
|
|
## Announce the actions & their descriptions on the XdndActionList &
|
|
## XdndActionDescription properties...
|
|
##
|
|
_announce_action_list $_dodragdrop_drag_source $_dodragdrop_actions \
|
|
$_dodragdrop_action_descriptions
|
|
|
|
##
|
|
## Arrange selection handlers for our drag source, and all the supported types
|
|
##
|
|
#DBG debug "xdnd::_dodragdrop: registerSelectionHandler $source $types"
|
|
registerSelectionHandler $source $types
|
|
|
|
##
|
|
## Step 1: When a drag begins, the source takes ownership of XdndSelection.
|
|
##
|
|
#DBG debug "xdnd::_dodragdrop: selection own $source"
|
|
selection own -command ::tkdnd::xdnd::_selection_ownership_lost \
|
|
-selection XdndSelection $source
|
|
set _dragging 1
|
|
|
|
## Grab the mouse pointer...
|
|
#DBG debug "xdnd::_dodragdrop: _grab_pointer $source [_get_mapped_cursor $_dodragdrop_default_action]"
|
|
_grab_pointer $source [_get_mapped_cursor $_dodragdrop_default_action]
|
|
|
|
## Register our generic event handler...
|
|
# The generic event callback will report events by modifying variable
|
|
# ::xdnd::_dodragdrop_event: a dict with event information will be set as
|
|
# the value of the variable...
|
|
#DBG debug "xdnd::_dodragdrop: _register_generic_event_handler"
|
|
_register_generic_event_handler
|
|
|
|
## Set a timeout for debugging purposes...
|
|
# after 60000 {set ::tkdnd::xdnd::_dragging 0}
|
|
|
|
#DBG debug "xdnd::_dodragdrop: waiting drag action to finish..."
|
|
tkwait variable ::tkdnd::xdnd::_dragging
|
|
#DBG debug "xdnd::_dodragdrop: drag action finished!"
|
|
_SendXdndLeave
|
|
|
|
set _dragging 0
|
|
#DBG debug "xdnd::_dodragdrop: _ungrab_pointer $source"
|
|
_ungrab_pointer $source
|
|
#DBG debug "xdnd::_dodragdrop: _unregister_generic_event_handler"
|
|
_unregister_generic_event_handler
|
|
catch {selection clear -selection XdndSelection}
|
|
#DBG debug "xdnd::_dodragdrop: unregisterSelectionHandler $source $types"
|
|
unregisterSelectionHandler $source $types
|
|
return $_dodragdrop_drop_target_accepts_action
|
|
};# xdnd::_dodragdrop
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_process_drag_events
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_process_drag_events {event} {
|
|
# The return value from proc is normally 0. A non-zero return value indicates
|
|
# that the event is not to be handled further; that is, proc has done all
|
|
# processing that is to be allowed for the event
|
|
variable _dragging
|
|
if {!$_dragging} {return 0}
|
|
#DBG debug "xdnd::_process_drag_events: $event"
|
|
|
|
variable _dodragdrop_time
|
|
set time [dict get $event time]
|
|
set type [dict get $event type]
|
|
if {$time < $_dodragdrop_time && ![string equal $type SelectionRequest]} {
|
|
#DBG debug "xdnd::_process_drag_events: return 0 (1)"
|
|
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]} {
|
|
## Examine the modifiers to suggest an action...
|
|
set _dodragdrop_default_action [_default_action $event]
|
|
## Is it a Tk widget?
|
|
#DBG set path [winfo containing $rootx $rooty]
|
|
#DBG debug "Window under mouse: $window ($path)"
|
|
if {$_dodragdrop_drop_target != $window} {
|
|
## Send XdndLeave to $_dodragdrop_drop_target
|
|
_SendXdndLeave
|
|
## Is there a proxy? If not, _find_drop_target_proxy returns the
|
|
## target window, so we always get a valid "proxy".
|
|
set proxy [_find_drop_target_proxy $_dodragdrop_drag_source $window]
|
|
## Send XdndEnter to $window
|
|
_SendXdndEnter $window $proxy
|
|
## Send XdndPosition to $_dodragdrop_drop_target
|
|
_SendXdndPosition $rootx $rooty $_dodragdrop_default_action
|
|
} else {
|
|
## Send XdndPosition to $_dodragdrop_drop_target
|
|
_SendXdndPosition $rootx $rooty $_dodragdrop_default_action
|
|
}
|
|
} else {
|
|
## No window under the mouse. Send XdndLeave to $_dodragdrop_drop_target
|
|
_SendXdndLeave
|
|
}
|
|
}
|
|
ButtonPress {
|
|
}
|
|
ButtonRelease {
|
|
variable _dodragdrop_button
|
|
set button [dict get $event button]
|
|
if {$button == $_dodragdrop_button} {
|
|
## The button that initiated the drag was released. Trigger drop...
|
|
#DBG debug "xdnd::_process_drag_events: _SendXdndDrop"
|
|
_SendXdndDrop
|
|
}
|
|
#DBG debug "xdnd::_process_drag_events: return 1 (2)"
|
|
# return 1 ;# Returning non-zero is not a good idea...
|
|
return 0
|
|
}
|
|
KeyPress {
|
|
}
|
|
KeyRelease {
|
|
set keysym [dict get $event keysym]
|
|
switch $keysym {
|
|
Escape {
|
|
## The user has pressed escape. Abort...
|
|
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
|
|
#DBG debug "xdnd::_process_drag_events: return 0 (3)"
|
|
return 0
|
|
}
|
|
default {
|
|
#DBG debug "xdnd::_process_drag_events: return 0 (4)"
|
|
return 0
|
|
}
|
|
}
|
|
#DBG debug "xdnd::_process_drag_events: return 0 (5)"
|
|
return 0
|
|
};# _process_drag_events
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_SendXdndEnter
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
#DBG debug "XdndEnter: $_dodragdrop_drop_target $_dodragdrop_drop_target_proxy"
|
|
_send_XdndEnter $_dodragdrop_drag_source $_dodragdrop_drop_target \
|
|
$_dodragdrop_drop_target_proxy $_dodragdrop_types
|
|
};# xdnd::_SendXdndEnter
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_SendXdndPosition
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
## Arrange a new XdndPosition, to be send periodically...
|
|
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}
|
|
#DBG debug "XdndPosition: $_dodragdrop_drop_target $rootx $rooty $action"
|
|
_send_XdndPosition $_dodragdrop_drag_source $_dodragdrop_drop_target \
|
|
$_dodragdrop_drop_target_proxy $rootx $rooty $action
|
|
set _dodragdrop_waiting_status 1
|
|
};# xdnd::_SendXdndPosition
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_HandleXdndStatus
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
#DBG debug "XdndStatus: $event"
|
|
};# xdnd::_HandleXdndStatus
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_HandleXdndFinished
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
}
|
|
#DBG debug "XdndFinished: $event"
|
|
};# xdnd::_HandleXdndFinished
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_SendXdndLeave
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_SendXdndLeave {} {
|
|
variable _dodragdrop_drag_source
|
|
variable _dodragdrop_drop_target
|
|
if {$_dodragdrop_drop_target < 1} return
|
|
variable _dodragdrop_drop_target_proxy
|
|
#DBG debug "XdndLeave: $_dodragdrop_drop_target"
|
|
_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
|
|
};# xdnd::_SendXdndLeave
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_SendXdndDrop
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_SendXdndDrop {} {
|
|
variable _dodragdrop_drag_source
|
|
variable _dodragdrop_drop_target
|
|
if {$_dodragdrop_drop_target < 1} {
|
|
## The mouse has been released over a widget that does not accept drops.
|
|
_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
|
|
}
|
|
#DBG debug "XdndDrop: $_dodragdrop_drop_target"
|
|
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
|
|
#DBG debug "XdndDrop: $_dodragdrop_drop_target"
|
|
## Arrange a timeout for receiving XdndFinished...
|
|
variable _dodragdrop_xdnd_finished_event_after_id
|
|
set _dodragdrop_xdnd_finished_event_after_id \
|
|
[after 10000 [list ::tkdnd::xdnd::_HandleXdndFinished {}]]
|
|
};# xdnd::_SendXdndDrop
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_update_cursor
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_update_cursor { {cursor {}}} {
|
|
#DBG debug "_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 [_get_mapped_cursor $cursor]
|
|
set _dodragdrop_current_cursor $cursor
|
|
}
|
|
};# xdnd::_update_cursor
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_get_mapped_cursor
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_get_mapped_cursor { cursor } {
|
|
variable _dodragdrop_cursor_map
|
|
variable _dodragdrop_drag_source
|
|
## Is there a custom cursor map?
|
|
if {[catch {dict get $_dodragdrop_cursor_map $cursor} mapped]} {
|
|
## Do not report the error, ignore the mapping.
|
|
set mapped $cursor
|
|
}
|
|
## Is there a cursor feedback command?
|
|
set cmd [bind $_dodragdrop_drag_source <<DragCursorFeedback>>]
|
|
if {$cmd ne ""} {
|
|
set code [catch {uplevel \#0 $cmd \{$_dodragdrop_drag_source\} \{$cursor\} \{$mapped\}} info options]
|
|
#DBG debug "CODE: $code ---- $info"
|
|
switch -exact -- $code {
|
|
0 {if {$info ne ""} {set mapped $info}}
|
|
default {
|
|
return -options $options $info
|
|
}
|
|
}
|
|
}
|
|
return $mapped
|
|
};# xdnd::_get_mapped_cursor
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_default_action
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
};# xdnd::_default_action
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::getFormatForType
|
|
# ----------------------------------------------------------------------------
|
|
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
|
|
};# xdnd::getFormatForType
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::registerSelectionHandler
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::registerSelectionHandler {source types} {
|
|
foreach type $types {
|
|
selection handle -selection XdndSelection \
|
|
-type $type \
|
|
-format [getFormatForType $type] \
|
|
$source [list ::tkdnd::xdnd::_SendData $type]
|
|
}
|
|
};# xdnd::registerSelectionHandler
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::unregisterSelectionHandler
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::unregisterSelectionHandler {source types} {
|
|
foreach type $types {
|
|
catch {
|
|
selection handle -selection XdndSelection \
|
|
-type $type \
|
|
-format [getFormatForType $type] \
|
|
$source {}
|
|
}
|
|
}
|
|
};# xdnd::unregisterSelectionHandler
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_convert_to_unsigned
|
|
# ----------------------------------------------------------------------------
|
|
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"}
|
|
}
|
|
## Convert signed integer into unsigned...
|
|
set d [list]
|
|
foreach num $data {
|
|
lappend d [expr { $num & $mask }]
|
|
}
|
|
return $d
|
|
};# xdnd::_convert_to_unsigned
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Command xdnd::_SendData
|
|
# ----------------------------------------------------------------------------
|
|
proc xdnd::_SendData {type offset bytes args} {
|
|
variable _dodragdrop_drag_source
|
|
variable _dodragdrop_types
|
|
variable _dodragdrop_data
|
|
variable _dodragdrop_transfer_data
|
|
|
|
## The variable _dodragdrop_data contains a list of data, one for each
|
|
## type in the _dodragdrop_types variable. We have to search types, and find
|
|
## the corresponding entry in the _dodragdrop_data list.
|
|
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} {
|
|
## Prepare the data to be transferred...
|
|
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
|
|
## Try to understand the provided data: we accept a standard Tk colour,
|
|
## or a list of 3 values (red green blue) or a list of 4 values
|
|
## (red green blue opacity).
|
|
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\""}
|
|
}
|
|
## Convert the 4 elements into 16 bit values...
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
##
|
|
## Data has been split into bytes. Count the bytes requested, and return them
|
|
##
|
|
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} {
|
|
## Tk selection cannot process this format (only 8 & 32 supported).
|
|
## Call our XChangeProperty...
|
|
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"
|
|
}
|
|
}
|
|
#DBG debug "SendData: $type $offset $bytes $args ($typed_data)"
|
|
#DBG debug " $data"
|
|
return $data
|
|
};# xdnd::_SendData
|