Commit 0fb14a00 authored by ROOL's avatar ROOL 🤖

Add copy & paste and drag & drop operations to the Wimp

Detail:
  The text in writable icons can now be manipulated using the familiar keyboard shortcuts, or using Drag and Drop in conjunction with any compliant applications.
  Further details are in Doc/DragAndDrop along with information on API extensions which are implemented.
Admin:
  Submission for Clipboard Support bounty.

Version 5.65. Tagged as 'Wimp-5_65'
parent 5a8c8508
Specification
=============
The specification covering the use of cut-and-paste and drag-and-drop in
writable icons is stored in RiscOS/Sources/Desktop/Clipboard.
writable icons is stored
https://www.riscosopen.org/wiki/documentation/show/Drag-And-Drop%20Functional%20Specification
WindowManager changes - Clipboard
=================================
In order to provide clipboard functionality, the Wimp has had some extra internal functionality added. Most of the extra calls will be of no major use to other tasks but documentation is supplied here for completeness. Key press handling changes may be relevant, however.
Key press handling
Certain extra key codes are intercepted and handled by the Wimp if the caret is in a writeable icon.
^C Copy selection to clipboard
^K Delete selection
^V Paste selection from clipboard
^X Cut selection to clipboard
Shift ^ left cursor Extend / shrink selection to the left*
Shift ^ right cursor Extend / shrink selection to the right*
* actual end of the selection that is adjusted depends on which part was last adjusted by the user.
If ^C is used in a password icon, no copy is made. Similarly, if ^X is used, no data is copied to the clipboard.
Should a task wish to receive these key codes for its own uses, then the above can be blocked by using the validation string KC. No clipboard selection actions will then take place.
SWIs
====
Wimp_Autoscroll (&400FD)
If bit 3 of the flags in R0 is set, then:
R0 flags
bit 0: 1=>enable horizontal scrolling; 0=>cancel scrolling
bit 3: set
All other bits ignored and should be considered reserved and set to 0.
R1 Pointer to data block
+0 Window handle
+4 Icon handle
On exit, registers preserved. On error, V set and R0 points to standard error block.
This call triggers autoscrolling of a writeable icon. It is used by the Wimp when a drag operation is in progress to scroll the icon when a ghost caret is being positioned.
Wimp_DragBox (&400D0)
Parameters unchanged.
Drag Box block in R1:
+0 Window handle
+4 13
+8-52 unused
Drag box type 13 has been added. Issuing this call will start a selection drag within an icon. The drag is performed on the icon which currently holds the caret. The exact type of selection drag depends on the last click event on the icon.
Wimp_Extend (&400FB)
There is an extra reason code added. It is primarily intended for internal use.
R0 14
R1 Window handle
R2 Icon handle
R3 Pointer to buffer for data if R4<>0
R4 Buffer size or 0 to get required size
On exit, if there is an error then R0 points to a standard error block and V is set.
R4 Space remaining in buffer. Will be negative if R4=0 on entry.
Unlike an indirection string there is no direct way of obtaining the length of an icon validation string from another task. This call allows a copy of the validation string to be obtained safely.
The buffer pointed to in R3 must not be in application space as it is very likely to be paged out. If there is not going to be enough space in the allocated buffer then nothing will be copied and the potential overflow count is returned.
This call should be used twice. On the first call, R4 should be set to 0. On exit, R4 will contain 0 if there is no validation string or a negative number of characters to indicate the buffer size required. R3 is ignored in this case.
On the second call, R3 should point to the newly allocated buffer of correct size and R4 gives the positive buffer size. The validation string is now copied.
Wimp_StartTask (&400DE)
There is a minor change to functionality.
If R0 on entry points to the module title string and the WindowManager task is not running, then the WindowManager task is started.
If any other task is started and the WindowManager task is not running, then the WindowManager task will also be started.
Wimp_SetCaretPosition (&400D2)
Implementation is the same as the Drag and Drop specification but with the addition of one extra variation.
Normally, an icon caret may be set to a particular coordinate by using:
R0 window handle
R1 icon handle
R2 X offset relative to work area origin
R3 Y offset relative to work area origin
R4 undefined
R5 -1
However, R4 is undefined and could be anything.
The additional functionality allows a ghost caret to be set to an icon by using a coordinate rather than a string index:
R0 window handle
R1 icon handle
R2 X offset relative to work area origin
R3 Y offset relative to work area origin
R4 Caret flags
bits 0-15 caret height in OS units
24 use a Wimp-drawn caret rather than the Font Manager caret
30 1 (for ghost caret)
All other bits should be 0
R5 -2
Message passing
===============
In order to enable clipboard and drag and drop functionality, the Wimp will intercept and redirect certain messages. These messages will not be received by their intended destination task but will be handled by the WindowManager task instead.
Message_DataLoad
Message_DataSave
If the destination icon is writeable and the filetype at +40 is TextFile (&FFF) then the message is redirected.
Message_Dragging
If the message is part of a new conversation (ie your_ref=0) and the destination icon is writeable and there is an option of a TextFile (&FFF) in the filetype list at +56 then the message is redirected.
Note that it is the reponsibility of each task to bounce Message_Dragging if they currently have a claim and the pointer moves over one of their writeable icons. A new conversation will then result and the Wimp will perform the interception. Once the pointer leaves the writeable icon, Message_Dragging will again be bounced and the original task can continue again.
Clipboard Manager task
======================
The Wimp will start up a task called Clipboard Manager if it is not running and another task is started (see Wimp_StartTask above).
The Clipboard Manager task handles clipboard operations and clipboard ownership functionality for the Wimp. It also handles drag and drop messaging. It operates as per the drag and drop fucntional specification.
Display buffering
=================
In order to reduce flicker, especially when dragging a selection within an icon, writeable icons are now buffered. On redraw, the output is written first to a memory buffer and then the resulting buffer is written out to the screen.
The memory buffer is pre-allocated on mode change to cover an icon of 256x26 pixels in size. Should a larger icon be plotted, then the buffer size will be increased.
Note that there will still be a flicker if there are other icons beneath the writeable icon, as these will be redrawn and then the writeable icon in the usual way.
Memory usage
============
The clipboard Wimp requires extra memory to hold the display buffer and any clipboard or drag and drop data.
If dynamic areas are supported, then this memory is held in a dynamic area which is limited to 8MB in size. Memory is only claimed for the clipboard or drag and drop if a store is required; the area size will be reduced as far as possible as soon as this usage is over.
If dynamic areas are not supported, then the memory is claimed from the RMA.
......@@ -9,12 +9,12 @@
GBLS Module_ApplicationDate
GBLS Module_HelpVersion
GBLS Module_ComponentName
Module_MajorVersion SETS "5.64"
Module_Version SETA 564
Module_MajorVersion SETS "5.65"
Module_Version SETA 565
Module_MinorVersion SETS ""
Module_Date SETS "14 Dec 2019"
Module_ApplicationDate SETS "14-Dec-19"
Module_ComponentName SETS "Wimp"
Module_FullVersion SETS "5.64"
Module_HelpVersion SETS "5.64 (14 Dec 2019)"
Module_FullVersion SETS "5.65"
Module_HelpVersion SETS "5.65 (14 Dec 2019)"
END
/* (5.64)
/* (5.65)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 5.64
#define Module_MajorVersion_CMHG 5.65
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 14 Dec 2019
#define Module_MajorVersion "5.64"
#define Module_Version 564
#define Module_MajorVersion "5.65"
#define Module_Version 565
#define Module_MinorVersion ""
#define Module_Date "14 Dec 2019"
......@@ -16,6 +16,6 @@
#define Module_ComponentName "Wimp"
#define Module_FullVersion "5.64"
#define Module_HelpVersion "5.64 (14 Dec 2019)"
#define Module_LibraryVersionInfo "5:64"
#define Module_FullVersion "5.65"
#define Module_HelpVersion "5.65 (14 Dec 2019)"
#define Module_LibraryVersionInfo "5:65"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -56,11 +56,13 @@ Module_BaseAddr
GET hdr:Switcher
GET hdr:PDriver
GET hdr:ScrBlank
GET hdr:OsBytes
GET hdr:OsWords
GET hdr:Countries
GET hdr:Internatio
GET hdr:VFPSupport
GET hdr:OSRSI6
GET hdr:OSMem
GET VersionASM
......@@ -109,4 +111,9 @@ LoadWimpOptions SETS "GET Options.s.$Options"
GET Trace.s
]
[ CnP
GET Clipboard.s
GET CBTask.s
]
END
......@@ -487,6 +487,9 @@ drag_subr_size * 9 ; user subr, variable size box
drag_subr_posn2 * 10 ; doesn't stop when buttons released
drag_subr_size2 * 11 ; doesn't stop when buttons released
drag_scrollboth * 12 ; drag both scroll bars
[ CnP
drag_icon_selection * 13 ; drag selection within writeable icon
]
[ Autoscr
dragf_anchor * 2_00000001 ; anchor rubber boxes to work area
......@@ -761,7 +764,9 @@ continueflag # 1 ; for changing extent while dragging
iconbar_needs_rs # 1
reentrancyflag # 1
old_escape # 1
[ CnP
cnp_ptr_writable # 1 ; if ptr_write is set, allows doubleclick to display properly
]
ALIGNHASH 4
[ ThreeDPatch
......@@ -871,7 +876,45 @@ oldclipx0 # 16 ; really x0,y0,x1,y1
hascaret # 4 ; 0 ==> this icon has the caret
careticonaddr # 4 ; address of icon with caret
caretx # 4 ; caret posn relative to text itself
[ :LNOT: CnP
caretscrollx # 4 ; text offset due to caret
]
[ CnP
cnp_drag_create_charselection * 1
cnp_drag_create_wordselection * 2
cnp_drag_dragdrop * 3
cnp_drag_adjust_high * 4
cnp_drag_adjust_low * 5
cnp_drag_limit * 5
caretx_dest # 4 ; where to store a new caretx value
hasghostcaret # 4 ; 0 ==> this icon has a ghost caret
ghostcaretx # 4
ghostcaretscrollxoverride # 4 ; if bignum then invalid, otherwise is a user provided scroll offset for the text origin
ghostcareticonaddr # 4
ghostcaretchecksum # 4 ; checksum of current text under ghost caret
clipboard_spritearea_num # 4
clipboard_spritearea_addr # 4
hasselection # 4 ; 0 ==> this icon has a selection
selectioniconaddr # 4 ; address of icon with selection
selectionwindowaddr # 4 ; selection window handle
cnp_buffered # 1 ; icon to be plotted is a writable that's going via a sprite buffer
cnp_clickcounter # 1 ; counter for double/triple click on writeable icon
cnp_pending_dragtype # 1 ; next select drag flavour
cnp_stacked_cliprect # 1 ; we stacked extra things to buffer output to sprite
; icon autoscroll bits
cnp_iconautoscr_state # 4 ; state of current icon autoscroll
cnp_iconautoscr_currentwindow # 4 ; current window handle for the scroll
cnp_iconautoscr_currenticon # 4 ; current icon handle for the scroll
cnp_iconautoscr_previous_x # 4 ; previous mouse X coord
cnp_iconautoscr_previous_y # 4 ; previous mouse y coord
cnp_iconautoscr_next_time # 4 ; next time we want to do something
cnp_iconautoscr_minoffset # 4 ; minimum scroll offset value for this icon
cnp_iconautoscr_maxoffset # 4 ; maximum scroll offset value for this icon
]
areaCBptr # 4
thisCBptr # 4
spritename # 4 ; ptr to sprite name (or header)
......@@ -1050,11 +1093,45 @@ crf_invisible * &02000000
crf_usercolour * &04000000
crf_realcolour * &08000000
[ CnP
crf_nocentre * &10000000
crf_ghostcaret * &40000000
crf_selection * &80000000
]
crb_colourshift * 16 ; use bits 16-23 for caret colour
[ CnP
caretdata # 24 ; window,icon,x,y coords,flags,index
; contents of caret block:
caretwindow * 0
careticon * 4
caretxoff * 8
caretyoff * 12
caretflags * 16
caretindex * 20
|
caretdata # 28 ; window,icon,x,y coords,height,index
; [caretdata+24]=caretscrollx (the definitive copy)
]
[ CnP
; this block must follow the caretdata block directly
ghostcaretdata # 24 ; window,icon,x,y coords,height,index
; contents of ghost caret block
ghostcaretwindow * 0
ghostcareticon * 4
ghostcaretxoff * 8
ghostcaretyoff * 12
ghostcaretflags * 16
ghostcaretindex * 20
]
oldcaretwindow # 4
[ CnP
redrawcaretwindow # 4
redrawcareticon # 4
refreshmaincaret # 4 ; we need to recalculate the caret coords for the main caret (on leaving setcaretposition)
]
menucaretwindow # 4
menucareticon # 4
oldcaretdata # 24 ; preserves caret data over menus
......@@ -1066,8 +1143,6 @@ appspacesize # 4 ; size of current application slot
]
[ CnP
ghostcaretdata # 28 ; window,icon,x,y coords,height,index
; [ghostcaretdata+24]=ghostcaretscrollx
selectionwindow # 4 ; external handle of the window that has the unshaded selection (or -1 if none)
font_cs_list # 4 ; for pointing to font control sequence list during pushfontstring
]
......@@ -1597,6 +1672,13 @@ errorbuttonoldhandlers # 3*3*4 ; old environment handlers to restore af
selecttable_lastpal # 1024 ; Last sprite palette used with selecttable
[ CnP
; workspace bits for running the task side of things for the clipboard
clipboard_taskhandle # 4 ; task handle for the front end task
clipboard_pollword # 4 ; pollword for the front end poll loop
selection_text_origin # 4 ; text origin for current unshaded selection window (if present)
]
maxwork * :INDEX:@
! 0, "Free pool = R12+&" :CC: :STR: :INDEX: freepool
......@@ -1616,17 +1698,17 @@ maxwork * :INDEX:@
[ CnP
! 0, "#ghostcaretdata = R12+&" :CC: :STR: :INDEX: ghostcaretdata
! 0, "#selectionwindow = R12+&" :CC: :STR: :INDEX: selectionwindow
! 0, "#clipboard_areanum = R12+&" :CC: :STR: :INDEX: clipboard_spritearea_num
! 0, "#pollword = R12+&" :CC: :STR: :INDEX: clipboard_pollword
]
[ Autoscr
! 0, "#dragtype = R12+&" :CC: :STR: :INDEX: dragtype
! 0, "#dragflags = R12+&" :CC: :STR: :INDEX: dragflags
! 0, "#autoscr_state = R12+&" :CC: :STR: :INDEX: autoscr_state
! 0, "#iconautoscrstate = R12+&" :CC: :STR: :INDEX: cnp_iconautoscr_state
]
! 0, "Workspace used &":CC::STR:maxwork:CC:" bytes."
;;-----------------------------------------------------------------------------
;; Format of data in a window definition
;;-----------------------------------------------------------------------------
......@@ -1653,8 +1735,21 @@ w_origflags # 4
]
[ CnP
w_seldata # 32 ; selection icon, x offset, width, y offset, height+flags, low,high indexes
] ; [w_seldata+28] = w_selscrollx
w_seldata # 36 ; selection icon, x offset, width, y offset, height+flags, low,high indexes
; [w_seldata+wselxoverride] = w_selscrollxoverride
; [w_seldata+wselchecksum] = selection checksum
; contents of window selection data block
wselicon * 0
wselxoff * 4
wselwidth * 8
wselyoff * 12
wselflags * 16
wsellowindex * 20
wselhighindex * 24
wselxoverride * 28
wselchecksum * 32
]
[ ChildWindows
w_bwax0 # 4 ; previous position/size (for toggling)
......@@ -2056,7 +2151,7 @@ Helpstr = "Window Manager",9,"$Module_HelpVersion"
[ standalone
= " (Stand alone)"
]
= module_postfix
= module_postfix
= 0
[ :LNOT: international_help
......@@ -3794,6 +3889,17 @@ gotwork
BL freetoolarea ; tidy the tool area
;
BL declareresourcefsfiles ; trap service call to pick them up
[ CnP
BL clipboard_create_sprite_area
ADRL R14,clipboard_taskhandle
MOV R0,#0
STR R0,[R14]
STR R0,cnp_iconautoscr_state
MOV R0,#-1
STR R0,cnp_iconautoscr_currenticon
MOV R0,#bignum
STR R0,ghostcaretscrollxoverride
]
BL recalcmodevars
;
exitinit1
......@@ -3965,6 +4071,10 @@ Die
MOV R1,WsPtr
SWI XOS_RemoveCallBack ; remove possible callback routine (may have been granted!)
;
[ CnP
BL clipboard_delete_sprite_area
]
;
Debug opn,"---- Debug closing down ----"
......@@ -4150,6 +4260,12 @@ Service2
MOVNE PC,LR
Push "LR" ; called on Service_Reset
[ CnP
ADRL R14,clipboard_taskhandle
MOV R1,#0
STR R1,[R14]
MOV R1,#Service_Reset
]
[ Medusa :LAND: :LNOT: DontCheckModeOnInit
; Reset currentmode on Service_Reset
; This allows us to get the correct mode in the case of a GraphicsV
......@@ -4408,6 +4524,11 @@ recalcmodevars
STR lr,tiling_sprite ; force re cache
]
]
[ CnP
BL clipboard_mode_changed
]
Pull R0
[ false
......@@ -6002,6 +6123,89 @@ doubleptr_on
ADR R2,ptr_double
B %FT01
[ CnP
ptr_write2
DCB "ptr_write2",0
ALIGN
ptr_write
DCB "ptr_write",0
ALIGN
doublewritable_on
; turn on double-writable pointer
; if the icon does not have a validation string, use ptr_double
; if it has Pptr_write, use ptr_write2
; if it has some other pointer, use ptr_double
ALTENTRY
; R10->window block
; R4=icon handle
; R5=icon flags
TST R5,#if_indirected
BEQ %FT99
; we are indirected.
; any validation string?
LDR R0,[handle,#w_icons]
ADD R0,R0,R4,LSL #i_shift
LDR R3,[R0,#i_data+4]
CMP R3,#0
BLE %FT99 ; no
; page in the task holding the icon
LDR R14,taskhandle
Push "R14"
LDR R14,[handle,#w_taskhandle]
Task R14,,"doublewriteable_on"
; see if there's a command code for ptr change
MOV R2,#WimpValidation_Pointer
BL findcommand
BNE %FT98 ; no
; see if the pointer name is ptr_write or not
ADR R2,ptr_write
88
LDRB R0,[R3],#1
CMP R0,#90 ; 'Z'
ORRLE R0,R0,#32
CMP R0,#65 ; 'A'
MOVLT R0,#0
LDRB R14,[R2],#1
TEQ R0,R14
BNE %FT98 ; mismatch
TEQ R0,#0
BNE %BT88
; validation is for ptr_write, so we're good
MOV R2,#1
STRB R2,cnp_ptr_writable
ADR R2,ptr_write2
Pull "R14"
Task R14,,"doublewriteable_finished1"
B %FT01 ; carry on setting pointer shape
98
; restore previous state
Pull "R14"
Task R14,,"doublewriteable_finished2"
99
MOV R2,#0
STRB R2,cnp_ptr_writable
ADR R2,ptr_double
B %FT01 ; set pointer shape
doublewritable_off
; turn off double-writable pointer shape
; revert to ptr_default or ptr_write depending on previous status
ALTENTRY
LDRB R2,cnp_ptr_writable
TEQ R2,#1
ADREQ R2,ptr_write
ADRNE R2,ptr_default
B %FT01
]
doubleptr_off
ALTENTRY
......
......@@ -3519,6 +3519,31 @@ setfontcolours
Pull "R0-R3, PC"
[ CnP
;; If we have a parked Message_DataLoad, certain calls need to clear it
;; but only if the recipient task hasn't called Wimp_Poll
;; (which will set the poll word)
cnp_clear_parked_dataload
Push "R0,R14"
LDR R14,clipboard_spritearea_addr
TEQ R14,#0
Pull "R0,PC",EQ ; no system in use, skip check
ADRL R14,clipboard_pollword
LDR R0,[R14]
TST R0,#clipboard_pw_dataload_flag
Pull "R0,PC",NE ; is active, do not touch
MOV R0,#0
LDR R14,clipboard_spritearea_addr
ADD R14,R14,#cnp_message_dataload_park
STR R0,[R14] ; clear the parked message
Pull "R0,PC"
]
;;-----------------------------------------------------------------------------
;; Force_Redraw - mark specified region invalid - will be redrawn later
;; Entry: R0 = window handle (if -1, then consider whole screen)
......@@ -3537,6 +3562,10 @@ SWIWimp_ForceRedraw
|
BVS ExitWimp ; this is pointless
]
[ CnP
BL cnp_clear_parked_dataload
]
;
MOV handle,R0 ; now only -1 => redraw whole screen
CMP handle,#-1 ; (-2 => redraw icon bar)
......@@ -3775,7 +3804,9 @@ crw5e
]
[ CnP
MOV R14, #nullptr
STR R14, [handle, #w_seldata] ; no icon contains a selection
STR R14, [handle, #w_seldata+wselicon] ; no icon contains a selection
MOV R14, #bignum
STR R14, [handle,#w_seldata+wselxoverride] ; no offset
]
; Window is now completely valid
......@@ -4287,11 +4318,23 @@ int_delete_window
;
BL byemessages ; R0 = window handle
; don't deliver messages for this one
[ CnP
Push "R11"
MOV R11,R0
BL clipboard_check_current_drag_op ; abort any selection drag in progress
Pull "R11"
]
MOV handle,R0
BL checkhandle
BLVC nocaret ; R0,handle = rel/abs handles
Pull "R1-R9,PC",VS
;
[ CnP
Push "R2"
MOV R2,#-1
BL cbtask_check_abort_drag ; abort any current icon text export drag
Pull "R2"
]
LDR R14,pending_window
TEQ R14,R0
BNE %FT01
......@@ -4412,11 +4455,47 @@ int_deleteicon
Rel R0,handle
LDR R14,caretdata
TEQ R14,R0
LDREQ R14,caretdata+4
LDREQ R14,caretdata+careticon
TEQEQ R14,R2 ; R2 not null!
MOVEQ R0,#nullptr
BLEQ int_set_caret_position ; turn off caret if nec.
;
[ CnP
BL cbtask_check_abort_drag ; stop any drag export if there's one running for this icon
LDR R14,ghostcaretdata
TEQ R14,R0
LDREQ R14,ghostcaretdata+ghostcareticon
TEQEQ R14,R2
BNE %FT01