📄 textsel.c
字号:
static const char CVSID[] = "$Id: textSel.c,v 1.12 2003/05/09 17:43:48 edg Exp $";/******************************************************************************** ** textSel.c - Selection and clipboard routines for NEdit text widget ** ** Copyright (C) 1999 Mark Edel ** ** This is free software; you can redistribute it and/or modify it under the ** terms of the GNU General Public License as published by the Free Software ** Foundation; either version 2 of the License, or (at your option) any later ** version. ** ** This software 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 General Public License ** for more details. ** ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple ** Place, Suite 330, Boston, MA 02111-1307 USA ** ** Nirvana Text Editor ** Dec. 15, 1995 ** ** Written by Mark Edel ** ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "textSel.h"#include "textP.h"#include "text.h"#include "textDisp.h"#include "textBuf.h"#include <stdio.h>#include <string.h>#include <limits.h>#include <Xm/Xm.h>#include <Xm/CutPaste.h>#include <Xm/Text.h>#include <X11/Xatom.h>#if XmVersion >= 1002#include <Xm/PrimitiveP.h>#endif#ifdef HAVE_DEBUG_H#include "../debug.h"#endif#define N_SELECT_TARGETS 7#define N_CLIP_TARGETS 4#define N_ATOMS 11enum atomIndex {A_TEXT, A_TARGETS, A_MULTIPLE, A_TIMESTAMP, A_INSERT_SELECTION, A_DELETE, A_CLIPBOARD, A_INSERT_INFO, A_ATOM_PAIR, A_MOTIF_DESTINATION, A_COMPOUND_TEXT};/* Results passed back to the convert proc processing an INSERT_SELECTION request, by getInsertSelection when the selection to insert has been received and processed */enum insertResultFlags {INSERT_WAITING, UNSUCCESSFUL_INSERT, SUCCESSFUL_INSERT};/* Actions for selection notify event handler upon receiving confermation of a successful convert selection request */enum selectNotifyActions {UNSELECT_SECONDARY, REMOVE_SECONDARY, EXCHANGE_SECONDARY}; /* temporary structure for passing data to the event handler for completing selection requests (the hard way, via xlib calls) */typedef struct { int action; XtIntervalId timeoutProcID; Time timeStamp; Widget widget; char *actionText; int length;} selectNotifyInfo;static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, char *deletedText, void *cbArg);static void sendSecondary(Widget w, Time time, Atom sel, int action, char *actionText, int actionTextLen);static void getSelectionCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format);static void getInsertSelectionCB(Widget w, XtPointer clientData,Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format);static void getExchSelCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format);static Boolean convertSelectionCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format);static void loseSelectionCB(Widget w, Atom *selType);static Boolean convertSecondaryCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format);static void loseSecondaryCB(Widget w, Atom *selType);static Boolean convertMotifDestCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format);static void loseMotifDestCB(Widget w, Atom *selType);static void selectNotifyEH(Widget w, XtPointer data, XEvent *event, Boolean *continueDispatch);static void selectNotifyTimerProc(XtPointer clientData, XtIntervalId *id);static Atom getAtom(Display *display, int atomNum);/*** Designate text widget "w" to be the selection owner for primary selections** in its attached buffer (a buffer can be attached to multiple text widgets).*/void HandleXSelections(Widget w){ int i; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; /* Remove any existing selection handlers for other widgets */ for (i=0; i<buf->nModifyProcs; i++) { if (buf->modifyProcs[i] == modifiedCB) { BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]); break; } } /* Add a handler with this widget as the CB arg (and thus the sel. owner) */ BufAddModifyCB(((TextWidget)w)->text.textD->buffer, modifiedCB, w);}/*** Discontinue ownership of selections for widget "w"'s attached buffer** (if "w" was the designated selection owner)*/void StopHandlingXSelections(Widget w){ int i; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; for (i=0; i<buf->nModifyProcs; i++) { if (buf->modifyProcs[i] == modifiedCB && buf->cbArgs[i] == w) { BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]); return; } }}/*** Copy the primary selection to the clipboard*/void CopyToClipboard(Widget w, Time time){ char *text; long itemID = 0; XmString s; int stat, length; /* Get the selected text, if there's no selection, do nothing */ text = BufGetSelectionText(((TextWidget)w)->text.textD->buffer); if (*text == '\0') { XtFree(text); return; } /* If the string contained ascii-nul characters, something else was substituted in the buffer. Put the nulls back */ length = strlen(text); BufUnsubstituteNullChars(text, ((TextWidget)w)->text.textD->buffer); /* Use the XmClipboard routines to copy the text to the clipboard. If errors occur, just give up. */ stat = XmClipboardStartCopy(XtDisplay(w), XtWindow(w), s=XmStringCreateSimple("NEdit"), time, w, NULL, &itemID); XmStringFree(s); if (stat != ClipboardSuccess) return;#ifdef notdef /* Note that we were previously passing length + 1 here, but I suspect that this was inconsistent with the somewhat ambiguous policy of including a terminating null but not mentioning it in the length */#endif if (XmClipboardCopy(XtDisplay(w), XtWindow(w), itemID, "STRING", text, length, 0, NULL) != ClipboardSuccess) { XtFree(text); return; } XtFree(text); XmClipboardEndCopy(XtDisplay(w), XtWindow(w), itemID);}/*** Insert the X PRIMARY selection (from whatever window currently owns it)** at the cursor position.*/void InsertPrimarySelection(Widget w, Time time, int isColumnar){ static int isColFlag; /* Theoretically, strange things could happen if the user managed to get in any events between requesting receiving the selection data, however, getSelectionCB simply inserts the selection at the cursor. Don't bother with further measures until real problems are observed. */ isColFlag = isColumnar; XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, getSelectionCB, &isColFlag, time);}/*** Insert the secondary selection at the motif destination by initiating** an INSERT_SELECTION request to the current owner of the MOTIF_DESTINATION** selection. Upon completion, unselect the secondary selection. If** "removeAfter" is true, also delete the secondary selection from the** widget's buffer upon completion.*/void SendSecondarySelection(Widget w, Time time, int removeAfter){ sendSecondary(w, time, getAtom(XtDisplay(w), A_MOTIF_DESTINATION), removeAfter ? REMOVE_SECONDARY : UNSELECT_SECONDARY, NULL, 0);}/*** Exchange Primary and secondary selections (to be called by the widget** with the secondary selection)*/void ExchangeSelections(Widget w, Time time){ if (!((TextWidget)w)->text.textD->buffer->secondary.selected) return; /* Initiate an long series of events: 1) get the primary selection, 2) replace the primary selection with this widget's secondary, 3) replace this widget's secondary with the text returned from getting the primary selection. This could be done with a much more efficient MULTIPLE request following ICCCM conventions, but the X toolkit MULTIPLE handling routines can't handle INSERT_SELECTION requests inside of MULTIPLE requests, because they don't allow access to the requested property atom in inside of an XtConvertSelectionProc. It's simply not worth duplicating all of Xt's selection handling routines for a little performance, and this would make the code incompatible with Motif text widgets */ XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, getExchSelCB, NULL, time);}/*** Insert the contents of the PRIMARY selection at the cursor position in** widget "w" and delete the contents of the selection in its current owner** (if the selection owner supports DELETE targets).*/void MovePrimarySelection(Widget w, Time time, int isColumnar){ static Atom targets[2] = {XA_STRING}; static int isColFlag; static XtPointer clientData[2] = {(XtPointer)&isColFlag, (XtPointer)&isColFlag}; targets[1] = getAtom(XtDisplay(w), A_DELETE); isColFlag = isColumnar; /* some strangeness here: the selection callback appears to be getting clientData[1] for targets[0] */ XtGetSelectionValues(w, XA_PRIMARY, targets, 2, getSelectionCB, clientData, time);}/*** Insert the X CLIPBOARD selection at the cursor position. If isColumnar,** do an BufInsertCol for a columnar paste instead of BufInsert.*/void InsertClipboard(Widget w, int isColumnar){ unsigned long length, retLength; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; int cursorLineStart, column, cursorPos; char *string; long id = 0; /* Get the clipboard contents. Note: this code originally used the CLIPBOARD selection, rather than the Motif clipboard interface. It was changed because Motif widgets in the same application would hang when users pasted data from nedit text widgets. This happened because the XmClipboard routines used by the widgets do blocking event reads, preventing a response by a selection owner in the same application. While the Motif clipboard routines as they are used below, limit the size of the data that be transferred via the clipboard, and are generally slower and buggier, they do preserve the clipboard across widget destruction and even program termination. */ if (XmClipboardInquireLength(XtDisplay(w), XtWindow(w), "STRING", &length) != ClipboardSuccess || length == 0) return; string = XtMalloc(length+1); if (XmClipboardRetrieve(XtDisplay(w), XtWindow(w), "STRING", string, length, &retLength, &id) != ClipboardSuccess || retLength == 0) { XtFree(string);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -