Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clipboard support in X11 #79

Open
dram opened this issue Oct 14, 2016 · 24 comments
Open

Clipboard support in X11 #79

dram opened this issue Oct 14, 2016 · 24 comments

Comments

@dram
Copy link
Contributor

dram commented Oct 14, 2016

Currently, Self use cut buffers to support copy&paste in X11, but KDE (maybe other some other WMs) do not support it.

I have to use xcutsel to manually transfer contents between cut buffers and selections.

P.S. xcb can be used to monitor cut buffers.

See https://en.wikipedia.org/wiki/X_Window_selection for more details about clipboards in X11.

@Bystroushaak
Copy link
Contributor

Confirmed also in linux Mint (mate/gnome2).

I can see the buffer in xcb, but it is not connected with buffer used by the GUI.

@Bystroushaak
Copy link
Contributor

I've managed to trace the clipboard calls to traits xlib display storeToClipboard: aString, which is basically wrapper over traits xlib display xStoreBytes: t0, which itself is just wrapper over C++ code defined in xlib_glue.cpp / XStoreBytes_wrap as:

void XStoreBytes_wrap(Display* display, char* buffer, void *FH) {
  if (!XStoreBytes(display, buffer, strlen(buffer))) {
    failure(FH, "xStoreBytes failed");
  }
}

That is clearly just another wrapper over XStoreBytes. I've found following description:

xstorebytes

I am no C++ programmer and definitlely no Unix / X11 expert, but from the description it looks to me like this is not a standard clipboard solution, but just some kind of X11 buffer.

@ghost
Copy link

ghost commented Oct 14, 2016

You want to use this: https://tronche.com/gui/x/xlib/window-information/selection.html

Store the text in a special buffer, then set some X11 window (doesn't Self always have one?) as the owner of the current X11 selection, and handle this event: https://tronche.com/gui/x/xlib/events/client-communication/selection-request.html by sending this back to the requesting window: https://tronche.com/gui/x/xlib/events/client-communication/selection.html

@dram
Copy link
Contributor Author

dram commented Oct 18, 2016

Just found that autocutsel can be used to temporarily bypass this problem, which will sync cut buffer and selection automatically.

For a complete solution, we need to update to mechanism mentioned by @pjanouch.

@Bystroushaak
Copy link
Contributor

I've did some research and I've found, that the @pjanouch is right, BUT the xlib code for main window is handled from the Self code*. So you have to do selection request, but somewhere from Self (traits xlib probably).

*There is xlibWindow.cpp, but that handles just monitor window and nothing else.

@Bystroushaak
Copy link
Contributor

I am not able to find where in the Self code is the event loop for the xlib. There seems to be too much objects and abstraction and generated code.

@doublec
Copy link
Collaborator

doublec commented Oct 22, 2016

I may be wrong but I think it's done by eventWatcher. See traits xWindow spawnEventWatcherProcess. This spawns a process that calls watch on a clone of globals eventWatcher attached to a display. That method does:

[ quiteFlag ] whileFalse: [ handler event: display nextEvent ].

display nextEvent calls the xlib routines for the xlib message loop.

The handler is from x11Globals window, which is a simpleEventHandler. There are methods in that for handling the various events. There's also a queuingEventHandler that can get used, I'm not sure when.

@Bystroushaak
Copy link
Contributor

Does this mean, that you can't modify the behavior while using Self, because the process is already launched? I've played with simpleEventHandler, but I was unable to get any reaction.

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

I suspect you need to find the actual instance of simpleEventHandler that is being used. Is it in a copy of x11Globals window?

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

Maybe I'm looking in the wrong place. desktop w winCanvases first gives a windowCanvas which has some objects that may help.

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

It looks like the handMorph does the heavy lifting. It has a getEventFromWindowCanvas: method that calls nextEvent from the windowCanvas mentioned in my previous comment. This returns the X11 event.

The getEventFromWindowCanvas is called from dispatchFrom in handMorph which converts it to a ui2Event. It then checks for various event types and forwards them to objects that have subscribed to event types. See handleAndForward:To: in handMorph for the methods it calls based on the event type.

worldMorph calls subscribeWindow to subscribe to window based events. It handles them in its windowEvent: method.

@Bystroushaak
Copy link
Contributor

Thanks, I will look at that.

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

And worldMorph has a processInputs method that "Processes any X events in the input queue". It iterates over the winCanvases calling dispatchFrom on the handMorph if it has any pending events.

processInputs is called from doSteps which is called from the world morph step loop started with forkStepProcess.

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

@Bystroushaak What do you think is a good place to document this sort of thing? The wiki?

@Bystroushaak
Copy link
Contributor

Bystroushaak commented Oct 23, 2016

The wiki needs refactoring, but I suppose it is the only place where we can collect documentation.

@russellallen
Copy link
Owner

An alternative option is that I could move the handbook to its own repo and give you all write access.

@Bystroushaak
Copy link
Contributor

I think that handbook should be more formal and definitive. For me, wiki is more experimental and temporary, better for collaboration.

@doublec
Copy link
Collaborator

doublec commented Oct 23, 2016

I added some notes to the wiki.

@Bystroushaak
Copy link
Contributor

Bystroushaak commented Oct 26, 2016

getEventFromWindowCanvas: seems like the right place for catching the events, at least for debuging and experimental purposes.

I've patched the xlib_glue.cpp with following code:

void XStoreBytes_wrap(Display* display, char* buffer, void *FH) {
  if (!XStoreBytes(display, buffer, strlen(buffer))) {
    failure(FH, "xStoreBytes failed");
  }

# ifdef XLIB
  // X11 clipboard support
  int revert_to;
  Window active_win;
  XGetInputFocus(display, &active_win, &revert_to);  // get active window

  XSetSelectionOwner(display, XA_PRIMARY, active_win, CurrentTime);
# endif // XLIB
}

Which should tell X11 to mark Self window as selection owner, and when other applications requests the selection (user press ctrl+v), it should send selection request event to Self as described in https://web.archive.org/web/20120125071034/http://michael.toren.net/mirrors/doc/X-copy+paste.txt

The problem is, that selection request doesn't ever appear. But it is defined in traits xlib events xEvent types as selectionRequest. But all requests start with letter x, so there is probably some translation from event numbers to classes. I think it may be in traits xlib events xEvent eventTypesDo:, which looks like some kind of registry for events:

| ee |
ee: xlib events.
blk value: ee xButtonPressedEvent     With: buttonPress.
blk value: ee xButtonReleasedEvent    With: buttonRelease.
blk value: ee xClientMessageEvent     With: clientMessage.
blk value: ee xColormapEvent          With: colormapNotify.
blk value: ee xConfigureEvent         With: configureNotify.
blk value: ee xEnterWindowEvent       With: enterNotify.
blk value: ee xExposeEvent            With: expose.
blk value: ee xFocusInEvent           With: focusIn. 
blk value: ee xFocusOutEvent          With: focusOut.
blk value: ee xGraphicsExposeEvent    With: graphicsExpose.
blk value: ee xKeyPressedEvent        With: keyPress.
blk value: ee xKeyReleasedEvent       With: keyRelease.
blk value: ee xLeaveWindowEvent       With: leaveNotify.
blk value: ee xMapEvent               With: mapNotify.
blk value: ee xMappingEvent           With: mappingNotify.
blk value: ee xMotionEvent            With: motionNotify.
blk value: ee xNoExposeEvent          With: noExpose.
blk value: ee xReparentEvent          With: reparentNotify.
blk value: ee xUnmapEvent             With: unmapNotify.
blk value: ee xVisibilityEvent        With: visibilityNotify.
self

All xEvents are generated by primitive maker, which is another confusing thing for me (where is the definition?).

So, I think the required steps are:

  • Make Self receive selectionRequest event as xSelectionRequest. This may require to add it to definition which the primitiveMaker is using to generate bindings.
  • Add C++ glue for response (as defined in X-copy+paste.txt). This could probably be done from Self itself, but it would probably require to generate more glue.

Off course, there is also strong probability, that I don't understand what I am doing deep enough and this is all nonsense :)

@doublec
Copy link
Collaborator

doublec commented Oct 26, 2016

That looks right to me. See the types category of traits xlib events xEvent for the definition of visibilityNotify, etc. These are the xlib event numbers. Initialisation code runs eventTypesDo: to map this to the xVisibilityEvent, etc. So adding an xSelectionRequest, an entry in eventTypesDo; and a name/number in that trait would hopefully work to propogate the event through.

For the primitiveMaker stuff you'll need to add the entry for the event,following the examples that are there, in xlibTemplates.self, then run from a Self shell:

'glue/xlibTemplates.self' _RunScript

This generates the xlib glue code and you can rebuild the image.

@Bystroushaak
Copy link
Contributor

Hah. Yeah, I just discovered same thing. I am trying to generate the xSelectionRequestEvent, via primitive maker but so far I didn't yet managed to generate it right.

@russellallen
Copy link
Owner

Can I request that anything you put anything you learn about primitive maker onto the wiki? :)

@doublec
Copy link
Collaborator

doublec commented Oct 26, 2016

I'll do a stub based on what I learned doing the font primitives.

@doublec
Copy link
Collaborator

doublec commented Oct 26, 2016

See primitiveMaker in the wiki.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants