私の目的はVulkanのためなのですが, ノートを書いておきます.
インストールしたXubuntuにはライブラリがないようなので, 以下のようにインストールします.
sudo apt install libxcb-xkb-dev sudo apt install libxcb-icccm4-dev
ウィンドウのサイズ変更をさせたくないため, xcb_icccm_set_wm_size_hintsで最小と最大を設定しています.
そのため, libxcb-icccmをリンクしています. ついでにXlibのコンパイルコマンドも書いておきました.
clang++ -std=c++11 -DLIME_USE_XCB -lxcb -lxcb-icccm Window.cpp main.cpp clang++ -std=c++11 -DLIME_USE_XLIB -lX11 Window.cpp main.cpp
#ifndef INC_LGRAPHICS_WINDOW_H_ #define INC_LGRAPHICS_WINDOW_H_ /** @file Window.h @author t-sakai @date 2017/11/03 */ #ifndef LASSERT #include <cassert> #endif #ifndef _MSC_VER #include <cstdint> #endif #ifdef LIME_USE_WIN32 #include <Windows.h> #endif #ifdef LIME_USE_XCB #include <xcb/xcb.h> #endif #ifdef LIME_USE_XLIB #include <X11/Xlib.h> #include <X11/Xutil.h> #endif #ifndef NULL # ifdef __cplusplus # if 201103L<=__cplusplus || 1900<=_MSC_VER # define NULL nullptr # else # define NULL 0 # endif # else # define NULL (void*)0 # endif #endif #ifndef LASSERT #ifdef _DEBUG #define LASSERT(exp) assert(exp) #else #define LASSERT(exp) #endif #endif namespace lgfx { #ifdef _MSC_VER typedef __int16 s16; typedef __int32 s32; typedef unsigned __int16 u16; typedef unsigned __int32 u32; #else typedef int16_t s16; typedef int32_t s32; typedef uint16_t u16; typedef uint32_t u32; #endif class Window { public: #ifdef LIME_USE_WIN32 typedef MSG Event; typedef HWND Handle; struct InitParam { u32 width_; u32 height_; u32 style_; u32 exStyle_; WNDPROC wndProc_; const char* title_; bool windowed_; }; #endif #ifdef LIME_USE_XCB typedef xcb_generic_event_t* Event; typedef xcb_window_t Handle; struct InitParam { u16 width_; u16 height_; const char* title_; }; #endif #ifdef LIME_USE_XLIB typedef XEvent Event; typedef ::Window Handle; struct InitParam { u32 width_; u32 height_; const char* title_; }; #endif #ifdef LIME_USE_WIN32 bool peekEvent(HWND hDlg, Event& ev); #endif #ifdef LIME_USE_XCB xcb_connection_t* getConnection(); #endif #ifdef LIME_USE_XLIB Display* getDisplay(); #endif struct Vector2 { s32 x_; s32 y_; }; Window(); ~Window(); bool create(InitParam& param); void destroy(); const Handle getHandle() const; Handle getHandle(); void setShow(bool show); Vector2 getViewSize(); bool peekEvent(Event& ev); private: Window(const Window&) = delete; Window& operator=(const Window&) = delete; #ifdef LIME_USE_WIN32 Handle handle_; #endif #ifdef LIME_USE_XCB xcb_connection_t* connection_; Handle handle_; xcb_intern_atom_reply_t* delete_; u16 width_; u16 height_; #endif #ifdef LIME_USE_XLIB Display* display_; Handle handle_; Atom delete_; s32 width_; s32 height_; #endif }; } #endif //INC_LGRAPHICS_WINDOW_H_
/** @file Window.cpp @author t-sakai @date 2017/11/03 */ #include "Window.h" #ifdef LIME_USE_XCB #include <xcb/xcb_icccm.h> #include <stdlib.h> #include <string.h> #endif #ifdef LIME_USE_XLIB #include <X11/Xatom.h> #include <string.h> #endif namespace lgfx { namespace { #ifdef LIME_USE_WIN32 const char* CLASSNAME_ = "LWINDOW"; static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wPara, LPARAM lParam); #endif } Window::Window() #ifdef LIME_USE_WIN32 :handle_(NULL) #endif #ifdef LIME_USE_XCB :connection_(NULL) ,handle_(0) ,delete_(NULL) #endif #ifdef LIME_USE_XLIB :display_(NULL) ,handle_(0) #endif { } Window::~Window() { destroy(); } bool Window::create(InitParam& param) { LASSERT(NULL == handle_); LASSERT(NULL != param.title_); #ifdef LIME_USE_WIN32 HINSTANCE hInstance = GetModuleHandle(0); //Create and register window class //----------------------------------------------------------- WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.lpfnWndProc = (NULL == param.wndProc_)? WndProc : param.wndProc_; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_WINLOGO); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = CLASSNAME_; wcex.hIconSm = LoadIcon(wcex.hInstance, NULL); if(!RegisterClassEx(&wcex)){ return false; } RECT rect; rect.left = 0; rect.top = 0; rect.right = param.width_; rect.bottom = param.height_; u32 style = param.style_; u32 exStyle = param.exStyle_; if(param.windowed_){ exStyle |= WS_EX_CLIENTEDGE; style |= WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_VISIBLE; }else{ style |= WS_POPUP | WS_VISIBLE; exStyle |= WS_EX_APPWINDOW; ShowCursor(FALSE); } AdjustWindowRectEx(&rect, style, FALSE, exStyle); handle_ = CreateWindowEx( exStyle, CLASSNAME_, param.title_, style, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL); if(NULL == handle_){ UnregisterClass(CLASSNAME_, hInstance); return false; } UpdateWindow(handle_); SetFocus(handle_); #endif #ifdef LIME_USE_XCB int screenIndex = 0; connection_ = xcb_connect(NULL, &screenIndex); if(xcb_connection_has_error(connection_)){ connection_ = NULL; return false; } const xcb_setup_t* setup = xcb_get_setup(connection_); xcb_screen_iterator_t screenIterator = xcb_setup_roots_iterator(setup); for(int i=0; i<screenIndex; ++i){ xcb_screen_next(&screenIterator); } xcb_screen_t* screen = screenIterator.data; handle_ = xcb_generate_id(connection_); u32 valueList[] = { screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY, }; xcb_create_window( connection_, XCB_COPY_FROM_PARENT, handle_, screen->root, -1, -1, param.width_, param.height_, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, valueList); xcb_flush(connection_); xcb_change_property( connection_, XCB_PROP_MODE_REPLACE, handle_, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(param.title_), param.title_); xcb_intern_atom_cookie_t protocols_cookie = xcb_intern_atom(connection_, 1, 12, "WM_PROTOCOLS"); xcb_intern_atom_reply_t* protocol_reply = xcb_intern_atom_reply(connection_, protocols_cookie, 0); xcb_intern_atom_cookie_t delete_cookie = xcb_intern_atom(connection_, 0, 16, "WM_DELETE_WINDOW"); delete_ = xcb_intern_atom_reply(connection_, delete_cookie, 0); xcb_change_property(connection_, XCB_PROP_MODE_REPLACE, handle_, (*protocol_reply).atom, 4, 32, 1, &(*delete_).atom); free(protocol_reply); xcb_size_hints_t hints; xcb_icccm_size_hints_set_min_size(&hints, param.width_, param.height_); xcb_icccm_size_hints_set_max_size(&hints, param.width_, param.height_); xcb_icccm_set_wm_size_hints(connection_, handle_, XCB_ATOM_WM_NORMAL_HINTS, &hints); width_ = param.width_; height_ = param.height_; xcb_map_window(connection_, handle_); xcb_flush(connection_); #endif #ifdef LIME_USE_XLIB display_ = XOpenDisplay(NULL); if(NULL == display_){ return false; } int default_screen = DefaultScreen(display_); handle_ = XCreateWindow( display_, DefaultRootWindow(display_), -1, -1, param.width_, param.height_, 0, //border width CopyFromParent, //color depth InputOutput, // DefaultVisual(display_, DefaultScreen(display_)), 0, NULL); if(handle_<=0){ XCloseDisplay(display_); display_ = NULL; return false; } //------------------------ XTextProperty name; name.value = reinterpret_cast<unsigned char*>(const_cast<char*>(param.title_)); name.encoding = XA_STRING; name.format = 8; name.nitems = strlen(param.title_); XSetWMName(display_, handle_, &name); delete_ = XInternAtom(display_, "WM_DELETE_WINDOW", false); XSetWMProtocols(display_, handle_, &delete_, 1); XSelectInput(display_, handle_, ExposureMask | StructureNotifyMask); XSizeHints hints; hints.min_width = param.width_; hints.min_height = param.height_; hints.max_width = param.width_; hints.max_height = param.height_; hints.flags = PMinSize | PMaxSize; XSetWMNormalHints(display_, handle_, &hints); width_ = static_cast<s32>(param.width_); height_ = static_cast<s32>(param.height_); XClearWindow(display_, handle_); XMapWindow(display_, handle_); #endif return true; } void Window::destroy() { #ifdef LIME_USE_WIN32 if(NULL != handle_){ DestroyWindow(handle_); handle_ = NULL; UnregisterClass(CLASSNAME_, GetModuleHandle(0)); } #endif #ifdef LIME_USE_XCB if(NULL != delete_){ free(delete_); delete_ = NULL; } if(NULL != connection_){ xcb_destroy_window(connection_, handle_); xcb_disconnect(connection_); handle_ = 0; connection_ = NULL; } #endif #ifdef LIME_USE_XLIB if(NULL != display_){ XDestroyWindow(display_, handle_); XCloseDisplay(display_); handle_ = 0; display_ = NULL; } #endif } const Window::Handle Window::getHandle() const { return handle_; } Window::Handle Window::getHandle() { return handle_; } void Window::setShow(bool show) { #ifdef LIME_USE_WIN32 ShowWindow(handle_, (show)?SW_SHOW : SW_HIDE); #endif #ifdef LIME_USE_XCB if(show){ xcb_map_window(connection_, handle_); }else{ xcb_unmap_window(connection_, handle_); } #endif #ifdef LIME_USE_XLIB if(show){ XMapWindow(display_, handle_); }else{ XUnmapWindow(display_, handle_); } #endif } Window::Vector2 Window::getViewSize() { #ifdef LIME_USE_WIN32 RECT rect; s32 width, height; if(TRUE == GetClientRect(handle_, &rect)){ width = rect.right - rect.left; height = rect.bottom - rect.top; }else{ width = 1; height = 1; } return {width, height}; #endif #ifdef LIME_USE_XCB xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connection_, handle_); xcb_get_geometry_reply_t* geom = xcb_get_geometry_reply(connection_, cookie, NULL); s32 width = geom->width - geom->border_width*2; s32 height = geom->height - geom->border_width*2; free(geom); return {width, height}; #endif #ifdef LIME_USE_XLIB s32 x; s32 y; s32 width=1; s32 height=1; ::Window root; u32 border; u32 depth; XGetGeometry(display_, handle_, &root, &x, &y, reinterpret_cast<u32*>(&width), reinterpret_cast<u32*>(&height), &border, //border &depth);//depth return {width, height}; #endif } bool Window::peekEvent(Event& ev) { #ifdef LIME_USE_WIN32 while(PeekMessage(&ev, NULL, 0, 0, PM_REMOVE)){ if(ev.message==WM_QUIT) return false; TranslateMessage(&ev); DispatchMessage(&ev); } return true; #endif #ifdef LIME_USE_XCB for(;;){ ev = xcb_poll_for_event(connection_); if(NULL == ev){ return true; } switch(ev->response_type & 0x7F){ case XCB_CONFIGURE_NOTIFY: break; case XCB_CLIENT_MESSAGE: if((*(xcb_client_message_event_t*)ev).data.data32[0] == (*delete_).atom){ return false; } break; } } //for(;;) #endif #ifdef LIME_USE_XLIB while(XPending(display_)){ XNextEvent(display_, &ev); switch(ev.type){ case ConfigureNotify: break; case DestroyNotify: return false; case ClientMessage: if(static_cast<u32>(ev.xclient.data.l[0]) == delete_){ return false; } break; } } //while(XPending return true; #endif } #ifdef LIME_USE_WIN32 bool Window::peekEvent(HWND hDlg, Event& ev) { while(PeekMessage(&ev, NULL, 0, 0, PM_REMOVE)){ if(ev.message==WM_QUIT) return false; if(NULL != hDlg && IsDialogMessage(hDlg, &ev)){ continue; } TranslateMessage(&ev); DispatchMessage(&ev); } return true; } #endif #ifdef LIME_USE_XCB xcb_connection_t* Window::getConnection() { return connection_; } #endif #ifdef LIME_USE_XLIB Display* Window::getDisplay() { return display_; } #endif namespace { #ifdef LIME_USE_WIN32 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_SYSCOMMAND: { switch(wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } break; //case WM_CLOSE: // DestroyWindow(hWnd); // break; case WM_PAINT: { ValidateRect(hWnd, NULL); } break; case WM_DESTROY: PostQuitMessage(0); return 1; break; default: return DefWindowProc(hWnd, msg, wParam, lParam); break; } return 0; } #endif } }
0 件のコメント:
コメントを投稿