diff --git a/CMakeLists.txt b/CMakeLists.txt index 48d7886..b97c080 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,16 @@ SET (TL_PROJECT_VERS 1.2.2) PROJECT (${TL_PROJECT_NAME} CXX C) -FIND_PACKAGE (X11) -IF (NOT X11_FOUND) - MESSAGE (FATAL_ERROR "Could not locate X11.") -ENDIF () +FIND_PACKAGE (PkgConfig) +PKG_CHECK_MODULES (PKG_XCB xcb) +PKG_CHECK_MODULES (PKG_XCB_ICCCM xcb-icccm) +PKG_CHECK_MODULES (PKG_XCB_KEYSYMS xcb-keysyms) -INCLUDE_DIRECTORIES (${X11_X11_INCLUDE_PATH}) +INCLUDE_DIRECTORIES ( + ${PKG_XCB_INCLUDE_DIRS} + ${PKG_XCB_ICCCM_INCLUDE_DIRS} + ${PKG_XCB_KEYSYMS_INCLUDE_DIRS} +) ADD_EXECUTABLE ( ${TL_PROJECT_NAME} @@ -23,7 +27,9 @@ ADD_EXECUTABLE ( TARGET_LINK_LIBRARIES ( ${TL_PROJECT_NAME} - ${X11_LIBRARIES} + ${PKG_XCB_LDFLAGS} + ${PKG_XCB_ICCCM_LDFLAGS} + ${PKG_XCB_KEYSYMS_LDFLAGS} ) INSTALL ( diff --git a/thingylaunch.cpp b/thingylaunch.cpp index 6cb7a8c..eac2fb4 100644 --- a/thingylaunch.cpp +++ b/thingylaunch.cpp @@ -24,9 +24,11 @@ * SUCH DAMAGE. */ -#include -#include -#include +#include +#include +#include +#include + #include #include #include @@ -50,7 +52,6 @@ class Thingylaunch { void run(int argc, char **argv); private: - void openDisplay(); void createWindow(); void setupDefaults(); void parseOptions(int argc, char **argv); @@ -58,24 +59,25 @@ class Thingylaunch { void eventLoop(); void grabHack(); void redraw(); - bool keypress(XKeyEvent * keyevent); + bool keyrelease(xcb_key_release_event_t * keyevent); void execcmd(); void die(std::string msg); - unsigned long parseColorName(std::string s); + uint32_t parseColorName(std::string s); private: /* X11 */ - std::string m_displayName; - Display * m_display; - GC m_gc; - GC m_rectgc; - Window m_win; - std::string m_fontName; - XFontStruct * m_fontInfo; - int m_screenNum; - unsigned long m_bgColor; - unsigned long m_fgColor; + xcb_connection_t * m_connection; + xcb_screen_t * m_screen; + int m_screenNum; + xcb_window_t m_win; + uint32_t m_bgColor; + uint32_t m_fgColor; + xcb_font_t m_font; + xcb_gcontext_t m_gc; + xcb_gcontext_t m_rectgc; + xcb_key_symbols_t * m_keysyms; + std::string m_fontName; /* Completion, history, and bookmarks */ Completion m_comp; @@ -94,18 +96,20 @@ Thingylaunch::Thingylaunch() Thingylaunch::~Thingylaunch() { +#if 0 XFreeFont(m_display, m_fontInfo); XFreeGC(m_display, m_gc); XFreeGC(m_display, m_rectgc); XUngrabKeyboard(m_display, CurrentTime); XDestroyWindow(m_display, m_win); - XCloseDisplay(m_display); +#endif + + xcb_disconnect(m_connection); } void Thingylaunch::run(int argc, char **argv) { - openDisplay(); createWindow(); setupDefaults(); @@ -127,56 +131,51 @@ main(int argc, char **argv) } void -Thingylaunch::openDisplay() -{ - try { - m_displayName = Util::getEnv("DISPLAY"); - } catch (std::runtime_error& e) { - die(e.what()); - } - - m_display = XOpenDisplay(m_displayName.c_str()); - if (m_display == NULL) { - die("Couldn't connect to DISPLAY"); - } - - m_screenNum = DefaultScreen(m_display); -} - -void Thingylaunch::createWindow() { + /* open connection to the display server */ + if ((m_connection = xcb_connect(NULL, &m_screenNum)) == nullptr) { + die("Couldn't connect to X11 server"); + } + m_screen = xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data; /* figure out the window location */ - int top { DisplayHeight(m_display, m_screenNum) / 2 - WINHEIGHT / 2 }; - int left { DisplayWidth(m_display, m_screenNum) / 2 - WINWIDTH / 2 }; + int top { m_screen->height_in_pixels / 2 - WINHEIGHT / 2 }; + int left { m_screen->width_in_pixels / 2 - WINWIDTH / 2 }; /* create the window */ - XSetWindowAttributes attrib; - attrib.override_redirect = True; - m_win = XCreateWindow(m_display, RootWindow(m_display, m_screenNum), left, top, WINWIDTH, WINHEIGHT, 0, - CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect, &attrib); - - /* set up the window hints etc */ - XSizeHints * win_size_hints = XAllocSizeHints(); - if (!win_size_hints) { - die("out of memory allocating hints"); - } - win_size_hints->flags = PMaxSize | PMinSize; - win_size_hints->min_width = win_size_hints->max_width = WINWIDTH; - win_size_hints->min_height = win_size_hints->max_height = WINHEIGHT; - XSetWMNormalHints(m_display, m_win, win_size_hints); - XFree(win_size_hints); + uint32_t mask { XCB_CW_EVENT_MASK }; + uint32_t value[] = { XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_RELEASE }; + + m_win = xcb_generate_id(m_connection); + xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_win, m_screen->root, + left, top, WINWIDTH, WINHEIGHT, 10, 0, + m_screen->root_visual, mask, value); + + /* set wm hints */ + xcb_size_hints_t hints = {0}; + hints.flags = XCB_ICCCM_SIZE_HINT_P_SIZE | XCB_ICCCM_SIZE_HINT_P_POSITION | XCB_ICCCM_SIZE_HINT_P_SIZE | + XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE; + hints.x = top; + hints.y = left; + hints.min_width = hints.max_width = WINWIDTH; + hints.min_height = hints.max_height = WINHEIGHT; + xcb_icccm_set_wm_normal_hints_checked(m_connection, m_win, &hints); + + /* allocate keysyms */ + m_keysyms = xcb_key_symbols_alloc(m_connection); /* map the window */ - XMapWindow(m_display, m_win); + xcb_map_window(m_connection, m_win); + + xcb_flush(m_connection); } void Thingylaunch::setupDefaults() { - m_bgColor = BlackPixel(m_display, m_screenNum); - m_fgColor = WhitePixel(m_display, m_screenNum); + m_bgColor = m_screen->black_pixel; + m_fgColor = m_screen->white_pixel; m_fontName = "-misc-*-medium-r-*-*-15-*-*-*-*-*-*-*"; } @@ -220,84 +219,72 @@ Thingylaunch::parseOptions(int argc, char **argv) } } -unsigned long +uint32_t Thingylaunch::parseColorName(std::string colorName) { - XColor tmp { 0 }; - XParseColor(m_display, DefaultColormap(m_display, m_screenNum), colorName.c_str(), &tmp); - XAllocColor(m_display, DefaultColormap(m_display, m_screenNum), &tmp); - return tmp.pixel; + auto lc = xcb_lookup_color(m_connection, m_screen->default_colormap, colorName.size(), colorName.c_str()); + auto lr = xcb_lookup_color_reply(m_connection, lc, NULL); + auto ac = xcb_alloc_color(m_connection, m_screen->default_colormap, lr->exact_red, lr->exact_green, lr->exact_blue); + auto ar = xcb_alloc_color_reply(m_connection, ac, NULL); + + uint32_t color { ar->pixel }; + + free(lr); + free(ar); + + return color; } void Thingylaunch::setupGC() { - int valuemask { 0 }; - int line_width { 1 }; - int line_style { LineSolid }; - int cap_style { CapButt }; - int join_style { JoinBevel }; - XGCValues values; - - /* GC for text */ - m_gc = XCreateGC(m_display, m_win, valuemask, &values); - XSetForeground(m_display, m_gc, m_fgColor); - XSetBackground(m_display, m_gc, m_bgColor); - XSetLineAttributes(m_display, m_gc, line_width, line_style, cap_style, join_style); - if ((m_fontInfo = XLoadQueryFont(m_display, m_fontName.c_str())) == nullptr) { - die("couldn't load font"); - } - XSetFont(m_display, m_gc, m_fontInfo->fid); - - /* GC for rectangle */ - m_rectgc = XCreateGC(m_display, m_win, valuemask, &values); - XSetForeground(m_display, m_rectgc, m_bgColor); - XSetBackground(m_display, m_rectgc, m_bgColor); + /* open font */ + m_font = xcb_generate_id(m_connection); + xcb_open_font(m_connection, m_font, m_fontName.size(), m_fontName.c_str()); + + /* create gc */ + uint32_t gcMask { XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH | XCB_GC_LINE_STYLE | XCB_GC_CAP_STYLE | XCB_GC_JOIN_STYLE | XCB_GC_FONT }; + uint32_t gcValues[] { m_fgColor, m_bgColor, 1, XCB_LINE_STYLE_SOLID, XCB_CAP_STYLE_BUTT, XCB_JOIN_STYLE_BEVEL, m_font }; + m_gc = xcb_generate_id(m_connection); + xcb_create_gc(m_connection, m_gc, m_win, gcMask, gcValues); + + /* create rectangle gc */ + uint32_t rectgcMask { XCB_GC_FOREGROUND | XCB_GC_BACKGROUND }; + uint32_t rectgcValues[] { m_bgColor, m_bgColor }; + m_rectgc = xcb_generate_id(m_connection); + xcb_create_gc(m_connection, m_rectgc, m_win, rectgcMask, rectgcValues); } void Thingylaunch::grabHack() { -#if 1 - struct timespec req; - req.tv_sec = 0; - req.tv_nsec = 5000000; - unsigned long maxwait { 3000000000UL }; /* 3 seconds */ - unsigned int i; + auto cookie = xcb_grab_keyboard(m_connection, 1, m_win, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + auto reply = xcb_grab_keyboard_reply(m_connection, cookie, NULL); - redraw(); - - /* this loop is required since pwm grabs the keyboard during the event loop */ - for (i = 0; i < (maxwait / req.tv_nsec); i++) { - nanosleep(&req, NULL); - if (XGrabKeyboard(m_display, m_win, False, GrabModeAsync, GrabModeAsync, CurrentTime) == 0) { - return; - } + if (reply && reply->status == XCB_GRAB_STATUS_SUCCESS) { + free(reply); + return; } - die("Couldn't grab keyboard"); -#else - XSetInputFocus(m_display, m_win, RevertToParent, CurrentTime); -#endif + xcb_set_input_focus(m_connection, XCB_INPUT_FOCUS_PARENT, m_win, XCB_CURRENT_TIME); } void Thingylaunch::eventLoop() { - XEvent e; - + xcb_generic_event_t * e; + xcb_key_release_event_t * ev; + redraw(); - XSelectInput(m_display, m_win, ExposureMask | KeyPressMask); - - for (;;) { - XNextEvent(m_display, &e); - switch(e.type) { - case Expose: + while ((e = xcb_wait_for_event(m_connection))) { + switch (e->response_type & ~0x80) { + case XCB_EXPOSE: redraw(); break; - case KeyPress: - if (keypress(&e.xkey)) { + case XCB_KEY_RELEASE: + ev = reinterpret_cast(e); + if (keyrelease(ev)) { return; } break; @@ -310,26 +297,46 @@ Thingylaunch::eventLoop() void Thingylaunch::redraw() { - int font_height { m_fontInfo->ascent + m_fontInfo->descent }; - int cursorLeft { XTextWidth(m_fontInfo, m_command.c_str(), m_cursorPos - m_command.begin()) }; +#if 1 + int font_height { 14 }; //m_fontInfo->ascent + m_fontInfo->descent }; + int cursorLeft { 0 }; //XTextWidth(m_fontInfo, m_command.c_str(), m_cursorPos - m_command.begin()) }; + + xcb_rectangle_t extRect { 0, 0, WINWIDTH, WINHEIGHT }; + xcb_rectangle_t intRect { 0, 0, WINWIDTH-1, WINHEIGHT-1 }; + + xcb_poly_fill_rectangle(m_connection, m_win, m_rectgc, 1, &extRect); + xcb_poly_rectangle(m_connection, m_win, m_gc, 1, &intRect); + + int16_t curRectX = cursorLeft + 2; + xcb_rectangle_t curRect { curRectX, 2, 2, 20 }; + xcb_poly_fill_rectangle(m_connection, m_win, m_gc, 1, &curRect); + + xcb_image_text_8(m_connection, m_command.size(), m_win, m_gc, 2, 2, m_command.c_str()); + + xcb_flush(m_connection); + +#else XFillRectangle(m_display, m_win, m_rectgc, 0, 0, WINWIDTH, WINHEIGHT); XDrawRectangle(m_display, m_win, m_gc, 0, 0, WINWIDTH-1, WINHEIGHT-1); XDrawString(m_display, m_win, m_gc, 2, font_height + 2, m_command.c_str(), m_command.size()); XDrawLine(m_display, m_win, m_gc, 2 + cursorLeft, font_height + 4, 2 + cursorLeft + 10, font_height + 4); XFlush(m_display); +#endif + + } bool -Thingylaunch::keypress(XKeyEvent * keyevent) +Thingylaunch::keyrelease(xcb_key_release_event_t * keyevent) { - char charPressed; - KeySym key_symbol; - - XLookupString(keyevent, &charPressed, 1, &key_symbol, NULL); + xcb_keysym_t key_symbol = xcb_key_symbols_get_keysym(m_keysyms, keyevent->detail, 0); + char charPressed = static_cast(key_symbol); + uint16_t modifiers = keyevent->state; /* check for an Alt-key meaning bookmark lookup */ - if (keyevent->state & Mod1Mask) { + if (modifiers >>4 & 1) { + std::cout << "ALT pressed" << std::endl; m_command = m_book.lookup(charPressed); if (!m_command.empty()) { m_hist.save(m_command); @@ -339,15 +346,16 @@ Thingylaunch::keypress(XKeyEvent * keyevent) } switch(key_symbol) { - case XK_Escape: + case 0x1B: // Escape exit(0); break; - case XK_BackSpace: + case 0x08: // Backspace m_comp.reset(); if (m_cursorPos != m_command.begin()) m_command.erase(--m_cursorPos); break; +#if 0 case XK_Left: case XK_KP_Left: @@ -426,6 +434,7 @@ Thingylaunch::keypress(XKeyEvent * keyevent) default: break; +#endif } /* normal printable chars including Latin-[1-8] + Keybad numbers */