summaryrefslogtreecommitdiffstats
path: root/zbar/processor/x.c
diff options
context:
space:
mode:
Diffstat (limited to 'zbar/processor/x.c')
-rw-r--r--zbar/processor/x.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/zbar/processor/x.c b/zbar/processor/x.c
new file mode 100644
index 0000000..7cb1a6e
--- /dev/null
+++ b/zbar/processor/x.c
@@ -0,0 +1,266 @@
+/*------------------------------------------------------------------------
+ * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include "posix.h"
+#include "processor.h"
+#include "window.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+static inline int x_handle_event(zbar_processor_t *proc)
+{
+ XEvent ev;
+ XNextEvent(proc->display, &ev);
+
+ switch (ev.type) {
+ case Expose: {
+ /* FIXME ignore when running(?) */
+ XExposeEvent *exp = (XExposeEvent *)&ev;
+ while (1) {
+ assert(ev.type == Expose);
+ _zbar_window_expose(proc->window, exp->x, exp->y, exp->width,
+ exp->height);
+ if (!exp->count)
+ break;
+ XNextEvent(proc->display, &ev);
+ }
+ zbar_window_redraw(proc->window);
+ break;
+ }
+
+ case ConfigureNotify:
+ zprintf(3, "resized to %d x %d\n", ev.xconfigure.width,
+ ev.xconfigure.height);
+ zbar_window_resize(proc->window, ev.xconfigure.width,
+ ev.xconfigure.height);
+ _zbar_processor_invalidate(proc);
+ break;
+
+ case ClientMessage:
+ if ((ev.xclient.message_type ==
+ XInternAtom(proc->display, "WM_PROTOCOLS", 0)) &&
+ ev.xclient.format == 32 &&
+ (ev.xclient.data.l[0] ==
+ XInternAtom(proc->display, "WM_DELETE_WINDOW", 0))) {
+ zprintf(3, "WM_DELETE_WINDOW\n");
+ return (_zbar_processor_handle_input(proc, -1));
+ }
+ break;
+
+ case KeyPress: {
+ KeySym key = XLookupKeysym(&ev.xkey, 0);
+ if (IsModifierKey(key))
+ break;
+ if ((key & 0xff00) == 0xff00)
+ key &= 0x00ff;
+ zprintf(16, "KeyPress(%04lx)\n", key);
+ /* FIXME this doesn't really work... */
+ return (_zbar_processor_handle_input(proc, key & 0xffff));
+ }
+ case ButtonPress: {
+ zprintf(16, "ButtonPress(%d)\n", ev.xbutton.button);
+ int idx = 1;
+ switch (ev.xbutton.button) {
+ case Button2:
+ idx = 2;
+ break;
+ case Button3:
+ idx = 3;
+ break;
+ case Button4:
+ idx = 4;
+ break;
+ case Button5:
+ idx = 5;
+ break;
+ }
+ return (_zbar_processor_handle_input(proc, idx));
+ }
+
+ case DestroyNotify:
+ zprintf(16, "DestroyNotify\n");
+ zbar_window_attach(proc->window, NULL, 0);
+ proc->xwin = 0;
+ return (0);
+
+ default:
+ /* ignored */;
+ }
+ return (0);
+}
+
+static int x_handle_events(zbar_processor_t *proc)
+{
+ int rc = 0;
+ while (rc >= 0 && XPending(proc->display))
+ rc = x_handle_event(proc);
+ return (rc);
+}
+
+static int x_connection_handler(zbar_processor_t *proc, int i)
+{
+ _zbar_mutex_lock(&proc->mutex);
+ _zbar_processor_lock(proc);
+ _zbar_mutex_unlock(&proc->mutex);
+
+ x_handle_events(proc);
+
+ _zbar_mutex_lock(&proc->mutex);
+ _zbar_processor_unlock(proc, 0);
+ _zbar_mutex_unlock(&proc->mutex);
+ return (0);
+}
+
+static int x_internal_handler(zbar_processor_t *proc, int i)
+{
+ XProcessInternalConnection(proc->display, proc->state->polling.fds[i].fd);
+ x_connection_handler(proc, i);
+ return (0);
+}
+
+static void x_internal_watcher(Display *display, XPointer client_arg, int fd,
+ Bool opening, XPointer *watch_arg)
+{
+ zbar_processor_t *proc = (void *)client_arg;
+ if (opening)
+ add_poll(proc, fd, x_internal_handler);
+ else
+ remove_poll(proc, fd);
+}
+
+int _zbar_processor_open(zbar_processor_t *proc, char *title, unsigned width,
+ unsigned height)
+{
+ proc->display = XOpenDisplay(NULL);
+ if (!proc->display)
+ return (err_capture_str(proc, SEV_ERROR, ZBAR_ERR_XDISPLAY, __func__,
+ "unable to open X display",
+ XDisplayName(NULL)));
+
+ add_poll(proc, ConnectionNumber(proc->display), x_connection_handler);
+ XAddConnectionWatch(proc->display, x_internal_watcher, (void *)proc);
+ /* must also flush X event queue before polling */
+ proc->state->pre_poll_handler = x_connection_handler;
+
+ int screen = DefaultScreen(proc->display);
+ XSetWindowAttributes attr;
+ attr.event_mask =
+ (ExposureMask | StructureNotifyMask | KeyPressMask | ButtonPressMask);
+
+ proc->xwin = XCreateWindow(proc->display, RootWindow(proc->display, screen),
+ 0, 0, width, height, 0, CopyFromParent,
+ InputOutput, CopyFromParent, CWEventMask, &attr);
+ if (!proc->xwin) {
+ XCloseDisplay(proc->display);
+ return (err_capture(proc, SEV_ERROR, ZBAR_ERR_XPROTO, __func__,
+ "creating window"));
+ }
+
+ XStoreName(proc->display, proc->xwin, title);
+
+ XClassHint *class_hint = XAllocClassHint();
+ class_hint->res_name = "zbar";
+ class_hint->res_class = "zbar";
+ XSetClassHint(proc->display, proc->xwin, class_hint);
+ XFree(class_hint);
+ class_hint = NULL;
+
+ Atom wm_delete_window = XInternAtom(proc->display, "WM_DELETE_WINDOW", 0);
+ if (wm_delete_window)
+ XSetWMProtocols(proc->display, proc->xwin, &wm_delete_window, 1);
+
+ if (zbar_window_attach(proc->window, proc->display, proc->xwin))
+ return (err_copy(proc, proc->window));
+ return (0);
+}
+
+int _zbar_processor_close(zbar_processor_t *proc)
+{
+ if (proc->window)
+ zbar_window_attach(proc->window, NULL, 0);
+
+ if (proc->display) {
+ if (proc->xwin) {
+ XDestroyWindow(proc->display, proc->xwin);
+ proc->xwin = 0;
+ }
+ proc->state->pre_poll_handler = NULL;
+ remove_poll(proc, ConnectionNumber(proc->display));
+ XCloseDisplay(proc->display);
+ proc->display = NULL;
+ }
+ return (0);
+}
+
+int _zbar_processor_invalidate(zbar_processor_t *proc)
+{
+ if (!proc->display || !proc->xwin)
+ return (0);
+ XClearArea(proc->display, proc->xwin, 0, 0, 0, 0, 1);
+ XFlush(proc->display);
+ return (0);
+}
+
+int _zbar_processor_set_size(zbar_processor_t *proc, unsigned width,
+ unsigned height)
+{
+ if (!proc->display || !proc->xwin)
+ return (0);
+
+ /* refuse to resize greater than (default) screen size */
+ XWindowAttributes attr;
+ XGetWindowAttributes(proc->display, proc->xwin, &attr);
+
+ int maxw = WidthOfScreen(attr.screen);
+ int maxh = HeightOfScreen(attr.screen);
+ int w, h;
+ if (width > maxw) {
+ h = (maxw * height + width - 1) / width;
+ w = maxw;
+ } else {
+ w = width;
+ h = height;
+ }
+ if (h > maxh) {
+ w = (maxh * width + height - 1) / height;
+ h = maxh;
+ }
+ assert(w <= maxw);
+ assert(h <= maxh);
+
+ XResizeWindow(proc->display, proc->xwin, w, h);
+ XFlush(proc->display);
+ return (0);
+}
+
+int _zbar_processor_set_visible(zbar_processor_t *proc, int visible)
+{
+ if (visible)
+ XMapRaised(proc->display, proc->xwin);
+ else
+ XUnmapWindow(proc->display, proc->xwin);
+ XFlush(proc->display);
+ return (0);
+}