/*------------------------------------------------------------------------ * Copyright 2007-2009 (c) Jeff Brown * * 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 "window.h" #include "processor.h" #include "posix.h" #include #include #include 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); }