]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/x11/drawcontext.cpp
Split platform-specific parts into separate directories
[libs/gui.git] / source / graphics / x11 / drawcontext.cpp
diff --git a/source/graphics/x11/drawcontext.cpp b/source/graphics/x11/drawcontext.cpp
new file mode 100644 (file)
index 0000000..e40390f
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdexcept>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xutil.h>
+#include "display_private.h"
+#include "drawcontext.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct DrawContext::Private
+{
+       XImage *image;
+       bool use_shm;
+       XShmSegmentInfo shminfo;
+};
+
+DrawContext::DrawContext(Window &w):
+       display(w.get_display()),
+       window(w),
+       priv(new Private)
+{
+       DisplayHandle dpy = display.get_private().display;
+
+       priv->use_shm = XShmQueryExtension(dpy);
+
+       XWindowAttributes wa;
+       XGetWindowAttributes(dpy, window.get_private().window, &wa);
+
+       if(priv->use_shm)
+       {
+               priv->image = XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &priv->shminfo, wa.width, wa.height);
+               if(!priv->image)
+                       throw runtime_error("XShmCreateImage");
+
+               priv->shminfo.shmid = shmget(IPC_PRIVATE, priv->image->bytes_per_line*priv->image->height, IPC_CREAT|0666);
+               priv->shminfo.shmaddr=priv->image->data = reinterpret_cast<char *>(shmat(priv->shminfo.shmid, 0, 0));
+               priv->shminfo.readOnly = false;
+
+               XShmAttach(dpy, &priv->shminfo);
+
+               XSync(dpy, false);
+               display.check_error();
+       }
+       else
+       {
+               priv->image = XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0);
+               if(!priv->image)
+                       throw runtime_error("XCreateImage");
+               priv->image->data = new char[priv->image->bytes_per_line*priv->image->height];
+       }
+}
+
+DrawContext::~DrawContext()
+{
+       if(priv->use_shm)
+       {
+               XShmDetach(display.get_private().display, &priv->shminfo);
+               shmdt(priv->shminfo.shmaddr);
+               shmctl(priv->shminfo.shmid, IPC_RMID, 0);
+       }
+
+       XDestroyImage(priv->image);
+
+       delete priv;
+}
+
+unsigned DrawContext::get_depth() const
+{
+       return priv->image->bits_per_pixel;
+}
+
+unsigned char *DrawContext::get_data()
+{
+       return reinterpret_cast<unsigned char *>(priv->image->data);
+}
+
+void DrawContext::update()
+{
+       DisplayHandle dpy = display.get_private().display;
+       WindowHandle wnd = window.get_private().window;
+
+       GC gc = XCreateGC(dpy, wnd, 0, 0);
+
+       if(priv->use_shm)
+               XShmPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height, false);
+       else
+               XPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height);
+
+       XFreeGC(dpy, gc);
+}
+
+} // namespace Graphics
+} // namespace Msp