diff options
| -rw-r--r-- | README.xwidget | 130 | ||||
| -rw-r--r-- | src/xwidget.c | 14 |
2 files changed, 87 insertions, 57 deletions
diff --git a/README.xwidget b/README.xwidget index 35b8d1c5232..77b98d5fd83 100644 --- a/README.xwidget +++ b/README.xwidget | |||
| @@ -14,18 +14,42 @@ will require adapter code for each type. | |||
| 14 | 14 | ||
| 15 | A difference from images is that xwidgets live their own life. You | 15 | A difference from images is that xwidgets live their own life. You |
| 16 | create them with an api, get a reference, and tie them to a particular | 16 | create them with an api, get a reference, and tie them to a particular |
| 17 | buffer with a display spec. Also, xwidgets exists in only one copy, | 17 | buffer with a display spec. |
| 18 | where a plain image can be shown in several windows. The xwidget code | 18 | |
| 19 | tries to handle this by essentialy making a screen capture of the | 19 | Each xwidget can have several views. In MVC terms, an xwidget is the |
| 20 | widget and displaying those in the non-active windows, and the live | 20 | model, and an xwidget-view is a view of the xwidget in a particular |
| 21 | widget in the active window. The current snapshot code doesnt work if | 21 | Emacs window. |
| 22 | the live xwidget is off-screen. This seems to be solveable by using | 22 | |
| 23 | the XComposite interface, but that doesnt currently work. | 23 | The xwidget code attempts to keep the visual appearance of the views |
| 24 | 24 | in sync with through an Observer pattern implementation. | |
| 25 | The current state is that one window, one frame, showing many xwidgets | 25 | |
| 26 | is a nice demo. One frame, many windows, will have lots of display | 26 | ** MVC and Xembedd |
| 27 | glitches. Many frames, many windows, will work even worse. | 27 | The MVC approach appears to be at least in principle robust for plain gtk |
| 28 | 28 | widgets. For the interesting case of gtk sockets which implements an | |
| 29 | xembed host widget that allows for embedding other applications inside | ||
| 30 | an Emacs window, the story gets more complex. | ||
| 31 | |||
| 32 | The problem is that xembed is designed to plug an application window | ||
| 33 | inside a a secket and thats it. You can't move a plug between | ||
| 34 | sockets. I tried numerous hacks to get around this but there is | ||
| 35 | nothing that works realy well. | ||
| 36 | |||
| 37 | Therefore the Emacs part of the code will only expose well-defined | ||
| 38 | interfaces. cooperating applications will be able to use the interface | ||
| 39 | in a well defined manner. The problem is that there is no known xembeddable | ||
| 40 | application that implement the needed type of functionality, which is | ||
| 41 | allowing for creating new windows on the fly that plug into new | ||
| 42 | sockets. | ||
| 43 | |||
| 44 | Therefore I will attempt to provide an external application that wraps | ||
| 45 | another application and through hacks attempts to provide the needed | ||
| 46 | multi view xembed function. That way Emacs is sane and the insanity | ||
| 47 | contained. | ||
| 48 | |||
| 49 | This app will work by providing a socket that an app plugs into. The | ||
| 50 | socket window is copied efficientlp by means of composition to a | ||
| 51 | number of other windows, that then are plugged into the different | ||
| 52 | Emacs sockets. | ||
| 29 | 53 | ||
| 30 | * Brief overview of how xwidgets work | 54 | * Brief overview of how xwidgets work |
| 31 | Xwidgets work in one way like images in Emacs. You bind a display spec very | 55 | Xwidgets work in one way like images in Emacs. You bind a display spec very |
| @@ -45,28 +69,10 @@ synchonous with Emacs display changes. Ok, so why is that difficult then? | |||
| 45 | xwidget is encountered during display, the flag is set. After redisplay, | 69 | xwidget is encountered during display, the flag is set. After redisplay, |
| 46 | iterate all xwidgets and hide those which hasnt been displayed. | 70 | iterate all xwidgets and hide those which hasnt been displayed. |
| 47 | 71 | ||
| 48 | - In the general case, there can only be one xwidget, and several views of | ||
| 49 | it. There is one live view, and several phantom views. The live view is defined | ||
| 50 | to be in the currently selected window. All other views are phantom views. | ||
| 51 | |||
| 52 | Even this simple rule is difficult to implement in practice because Emacs | ||
| 53 | display is clever and optimized. It is often difficult to know that a xwdiget | ||
| 54 | hasnt actually been displayed after a redisplay. | ||
| 55 | |||
| 56 | - phantom views of xwidgets are thankfully not so hard because gtk | ||
| 57 | supports snapshoting of many widget types. Snapshoting doesnt seem | ||
| 58 | to work if the live widget is offscreen. This might be solvable with | ||
| 59 | xcomposite, but attempts have so far failed. | ||
| 60 | |||
| 61 | - The gtk socket type for embedding external applications is desirable | 72 | - The gtk socket type for embedding external applications is desirable |
| 62 | but presents a lot of difficulties of its own. One difficulty is | 73 | but presents a lot of difficulties of its own. One difficulty is |
| 63 | deciding which input events to forward, and when and how to do it. | 74 | deciding which input events to forward, and when and how to do it. |
| 64 | 75 | ||
| 65 | - The case of showing an xwidget in several frames is not solved at all | ||
| 66 | currently. This would mean moving the live xwidget between frames when the | ||
| 67 | selected window moves. The gtk widget will need to be reparented between | ||
| 68 | windows, which seems fragile. | ||
| 69 | |||
| 70 | ** placement and clipping | 76 | ** placement and clipping |
| 71 | the entire emacs frame is a gtk window. we use the fixed layout | 77 | the entire emacs frame is a gtk window. we use the fixed layout |
| 72 | manager to place xwidgets on the frame. coordinates are supplied by | 78 | manager to place xwidgets on the frame. coordinates are supplied by |
| @@ -77,32 +83,14 @@ emacs frame. | |||
| 77 | this way was chosen to simplify clipping of the widgets against emacs | 83 | this way was chosen to simplify clipping of the widgets against emacs |
| 78 | window borders. | 84 | window borders. |
| 79 | 85 | ||
| 80 | ** xwidget phantom views in particular | ||
| 81 | The general aproach so far has been to have a "live" xwidget moved | ||
| 82 | around in the emacs window. when the selected window changes, the live | ||
| 83 | xwidget is moved there. the possibly other views of the xwidget are | ||
| 84 | called "phantoms" and are snapshoted from the live xwidget. | ||
| 85 | |||
| 86 | This turned out to be difficult and a lot of different aproaches has | ||
| 87 | been tried. The current, somewhat promising, aproach is to enable | ||
| 88 | composition for the xwidgets gtk widget peer. This enables renedering | ||
| 89 | of the widget to offscreen backing store. snapshoting then becomes | ||
| 90 | more robus, because otherwise snapshoting is dependent on the live | ||
| 91 | xwidget being on-screen, which isnt necesarily the case. | ||
| 92 | |||
| 93 | on the other hand, compositing introduces other issues. the live | ||
| 94 | xwidget isnt drawn automatically at all any more, so we need our own | ||
| 95 | expose handler to deal with drawing. this in turn enables us to toy | ||
| 96 | with transparency and such. | ||
| 97 | 86 | ||
| 98 | ** different strategies | 87 | ** different strategies |
| 99 | Integrating toolkit widgets(gtk in this case) and the emacs display | 88 | Integrating toolkit widgets(gtk in this case) and the emacs display |
| 100 | engine is more difficult than your plain average gui application, and | 89 | engine is more difficult than your plain average gui application, and |
| 101 | different strategies has been tested and will continue to be tested. | 90 | different strategies has been tested and will continue to be tested. |
| 102 | 91 | ||
| 103 | There will probably always be a distinction between live xwidgets and | 92 | There was a distinction between live xwidgets and |
| 104 | phantom xwidgets. how this distinction is realized has and will | 93 | phantom xwidgets, previous to the change to MVC. |
| 105 | change. | ||
| 106 | 94 | ||
| 107 | - the first aproach was to have the live xwidget on-screen, and move | 95 | - the first aproach was to have the live xwidget on-screen, and move |
| 108 | them about. the phantoms were generated by snapshoting the live | 96 | them about. the phantoms were generated by snapshoting the live |
| @@ -123,15 +111,13 @@ live and phantom widgets in different colors. | |||
| 123 | the drawback is that its our own responsibility to handle drawing, | 111 | the drawback is that its our own responsibility to handle drawing, |
| 124 | which puts more of the display optimization burden on us. | 112 | which puts more of the display optimization burden on us. |
| 125 | 113 | ||
| 126 | this is the currently tried aproach and it works so-so at the moment. | 114 | this is aproach worked so-so. |
| 127 | 115 | ||
| 128 | - another aproach is to have both live and phantom widgets drawn | 116 | - another aproach is to have both live and phantom widgets drawn |
| 129 | on-screen by proxy gtk objects. the live xwidget will be entirely | 117 | on-screen by proxy gtk objects. the live xwidget will be entirely |
| 130 | handled in an off-screen window, and the proxy objects will redirect | 118 | handled in an off-screen window, and the proxy objects will redirect |
| 131 | events there. | 119 | events there. |
| 132 | 120 | ||
| 133 | This aproach seems promising, but complicated. | ||
| 134 | |||
| 135 | - combine on-screen and off-screen aproaches. maybe composition is the | 121 | - combine on-screen and off-screen aproaches. maybe composition is the |
| 136 | way to go for most cases, but on-screen xembeding is the way to go | 122 | way to go for most cases, but on-screen xembeding is the way to go |
| 137 | for particular special cases, like showing video in a | 123 | for particular special cases, like showing video in a |
| @@ -139,6 +125,8 @@ This aproach seems promising, but complicated. | |||
| 139 | particular case, and the user will simply have to accept that the | 125 | particular case, and the user will simply have to accept that the |
| 140 | phantom of a video widget isnt particularily beautiful. | 126 | phantom of a video widget isnt particularily beautiful. |
| 141 | 127 | ||
| 128 | - The current and seemingly sanest aproach implements a MVC pattern. | ||
| 129 | |||
| 142 | ** Testing | 130 | ** Testing |
| 143 | ;;test like: | 131 | ;;test like: |
| 144 | ;; cd /path/to/xwidgets-emacs-dir | 132 | ;; cd /path/to/xwidgets-emacs-dir |
| @@ -176,11 +164,33 @@ work very well. | |||
| 176 | spent any time on it, since getting the visuals right is much | 164 | spent any time on it, since getting the visuals right is much |
| 177 | harder. Anyway, I sort of think the interface should be somewhat like | 165 | harder. Anyway, I sort of think the interface should be somewhat like |
| 178 | it is, except symbols is used instead of integers. | 166 | it is, except symbols is used instead of integers. |
| 167 | *** DONE use symbols for xwidget types rather than ints | ||
| 168 | CLOSED: [2011-06-27 Mon 12:52] | ||
| 169 | |||
| 170 | |||
| 171 | *** TODO better lisp based structure for xwidgets | ||
| 172 | something like this: | ||
| 173 | - a "process" like aproach to create the xwidgets. xwidgets are | ||
| 174 | coupled to buffers, somewhat like processes, except a buffer can | ||
| 175 | hold several xwidgets | ||
| 176 | - an xwidget has a plist to hold the model, like a process | ||
| 177 | - an xwidget has an assoc list of xwidget views | ||
| 178 | |||
| 179 | there are some things that arent clear: | ||
| 180 | - an xwidget doesnt necessarily need to be coupled to a buffer but it | ||
| 181 | seems to be the clearest model. xwidgets would be buffer local | ||
| 182 | - xwidget-views are by necessity coupled to a emacs window so it might | ||
| 183 | be better to store them window locally rather than in an assoc | ||
| 184 | coupled to the xwidget model | ||
| 185 | |||
| 186 | |||
| 179 | 187 | ||
| 180 | ** TODO more documentation | 188 | ** TODO more documentation |
| 181 | There should be user docs, and xwidget contributor docs. The current README | 189 | There should be user docs, and xwidget contributor docs. The current README |
| 182 | is all contributor docs there is now, apart from the code. | 190 | is all contributor docs there is now, apart from the code. |
| 183 | 191 | ||
| 192 | |||
| 193 | |||
| 184 | ** TODO look into more ways of displaying xwidgets, like binding them to a | 194 | ** TODO look into more ways of displaying xwidgets, like binding them to a |
| 185 | window rather than a point in a buffer. This was suggested by Chidong. | 195 | window rather than a point in a buffer. This was suggested by Chidong. |
| 186 | This would be a useful addition to Emacs in itself, and would avoid nearly all | 196 | This would be a useful addition to Emacs in itself, and would avoid nearly all |
| @@ -190,7 +200,8 @@ replace the view of a particular window, and it would only show in | |||
| 190 | that window. | 200 | that window. |
| 191 | 201 | ||
| 192 | 202 | ||
| 193 | ** TODO MVC mode for xwidgets | 203 | ** DONE MVC mode for xwidgets |
| 204 | CLOSED: [2011-06-27 Mon 12:53] | ||
| 194 | It appears unfruitful to chase using the same display mode for all | 205 | It appears unfruitful to chase using the same display mode for all |
| 195 | types of xwidgets. Composition is fun but not robust the way I'm | 206 | types of xwidgets. Composition is fun but not robust the way I'm |
| 196 | tried to do it. | 207 | tried to do it. |
| @@ -208,5 +219,14 @@ themselves. Inkscape supports multiple views to the same document, | |||
| 208 | other programs don't. In practice it might not be a big drawback. | 219 | other programs don't. In practice it might not be a big drawback. |
| 209 | 220 | ||
| 210 | 221 | ||
| 211 | *** TODO figure out what to do with the multiple frames case. | 222 | *** DONE figure out what to do with the multiple frames case. |
| 223 | CLOSED: [2011-06-27 Mon 12:52] | ||
| 212 | This should be easier to solve with MVC. | 224 | This should be easier to solve with MVC. |
| 225 | Surprisingly, this just worked! | ||
| 226 | *** DONE how to propagate changes in views to other views? | ||
| 227 | CLOSED: [2011-06-27 Mon 12:53] | ||
| 228 | I used gtk signals, the implementation for sliders works well! | ||
| 229 | |||
| 230 | ** TODO canvas support | ||
| 231 | goocanvas is a gtk canvas implemented with cairo. investigate. | ||
| 232 | http://developer.gnome.org/goocanvas/unstable/goocanvas-model-view-canvas.html | ||
diff --git a/src/xwidget.c b/src/xwidget.c index 1a0c23f5d9c..427004029d4 100644 --- a/src/xwidget.c +++ b/src/xwidget.c | |||
| @@ -362,7 +362,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 362 | int box_line_vwidth = max (s->face->box_line_width, 0); | 362 | int box_line_vwidth = max (s->face->box_line_width, 0); |
| 363 | int height = s->height; | 363 | int height = s->height; |
| 364 | 364 | ||
| 365 | int drawing_in_selected_window = (XWINDOW (FRAME_SELECTED_WINDOW (s->f))) == (s->w); | 365 | //int drawing_in_selected_window = (XWINDOW (FRAME_SELECTED_WINDOW (s->f))) == (s->w); |
| 366 | //TODO drawing_in_selected_window can be true for several windows if we have several frames. | 366 | //TODO drawing_in_selected_window can be true for several windows if we have several frames. |
| 367 | //we also need to check that the xwidget is to be drawn inside a window on a frame where it originaly lives. | 367 | //we also need to check that the xwidget is to be drawn inside a window on a frame where it originaly lives. |
| 368 | //otherwise draw a phantom, or maybe reparent the xwidget. | 368 | //otherwise draw a phantom, or maybe reparent the xwidget. |
| @@ -468,10 +468,11 @@ DEFUN ("xwidget-embed-steal-window", Fxwidget_embed_steal_window, Sxwidget_embed | |||
| 468 | 468 | ||
| 469 | 469 | ||
| 470 | DEFUN ("xwidget-resize-internal", Fxwidget_resize_internal, Sxwidget_resize_internal, 3, 3, 0, doc: | 470 | DEFUN ("xwidget-resize-internal", Fxwidget_resize_internal, Sxwidget_resize_internal, 3, 3, 0, doc: |
| 471 | ) | 471 | /* resize xwidgets */) |
| 472 | (Lisp_Object xwidget_id, Lisp_Object new_width, Lisp_Object new_height) | 472 | (Lisp_Object xwidget_id, Lisp_Object new_width, Lisp_Object new_height) |
| 473 | { | 473 | { |
| 474 | struct xwidget *xw; | 474 | struct xwidget *xw; |
| 475 | struct xwidget_view *xv; | ||
| 475 | int xid, w, h; | 476 | int xid, w, h; |
| 476 | 477 | ||
| 477 | CHECK_NUMBER (xwidget_id); | 478 | CHECK_NUMBER (xwidget_id); |
| @@ -491,6 +492,15 @@ DEFUN ("xwidget-resize-internal", Fxwidget_resize_internal, Sxwidget_resize_inte | |||
| 491 | gtk_widget_set_size_request (GTK_WIDGET (xw->widget), xw->width, | 492 | gtk_widget_set_size_request (GTK_WIDGET (xw->widget), xw->width, |
| 492 | xw->height); | 493 | xw->height); |
| 493 | */ | 494 | */ |
| 495 | for (int i = 0; i < MAX_XWIDGETS; i++) //TODO MVC refactor lazy linear search | ||
| 496 | { | ||
| 497 | xv = &xwidget_views[i]; | ||
| 498 | if(xv->model == xw){ | ||
| 499 | gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height); | ||
| 500 | gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 494 | return Qnil; | 504 | return Qnil; |
| 495 | } | 505 | } |
| 496 | 506 | ||