void wxTopLevelWindowGTK::GTKUpdateDecorSize(const DecorSize& decorSize) { if (!IsMaximized() && !IsFullScreen()) GetCachedDecorSize() = decorSize; if (m_updateDecorSize && memcmp(&m_decorSize, &decorSize, sizeof(DecorSize))) { m_useCachedClientSize = false; const wxSize diff( decorSize.left - m_decorSize.left + decorSize.right - m_decorSize.right, decorSize.top - m_decorSize.top + decorSize.bottom - m_decorSize.bottom); m_decorSize = decorSize; bool resized = false; if (m_minWidth > 0 || m_minHeight > 0 || m_maxWidth > 0 || m_maxHeight > 0) { // update size hints, they depend on m_decorSize DoSetSizeHints(m_minWidth, m_minHeight, m_maxWidth, m_maxHeight, m_incWidth, m_incHeight); } if (m_deferShow) { // keep overall size unchanged by shrinking m_widget int w, h; GTKDoGetSize(&w, &h); // but not if size would be less than minimum, it won't take effect if (w >= m_minWidth - (decorSize.left + decorSize.right) && h >= m_minHeight - (decorSize.top + decorSize.bottom)) { gtk_window_resize(GTK_WINDOW(m_widget), w, h); if (!gtk_window_get_resizable(GTK_WINDOW(m_widget))) gtk_widget_set_size_request(GTK_WIDGET(m_widget), w, h); resized = true; } } if (!resized) { // adjust overall size to match change in frame extents m_width += diff.x; m_height += diff.y; if (m_width < 1) m_width = 1; if (m_height < 1) m_height = 1; m_clientWidth = 0; gtk_widget_queue_resize(m_wxwindow); } } if (m_deferShow) { // gtk_widget_show() was deferred, do it now m_deferShow = false; DoGetClientSize(&m_clientWidth, &m_clientHeight); wxSizeEvent sizeEvent(GetSize(), GetId()); sizeEvent.SetEventObject(this); HandleWindowEvent(sizeEvent); gtk_widget_show(m_widget); wxShowEvent showEvent(GetId(), true); showEvent.SetEventObject(this); HandleWindowEvent(showEvent); } }
void wxTopLevelWindowGTK::GTKUpdateDecorSize(const wxSize& decorSize) { if (!IsMaximized() && !IsFullScreen()) GetCachedDecorSize() = decorSize; if (m_updateDecorSize && m_decorSize != decorSize) { const wxSize diff = decorSize - m_decorSize; m_decorSize = decorSize; bool resized = false; if (m_deferShow) { // keep overall size unchanged by shrinking m_widget int w, h; GTKDoGetSize(&w, &h); // but not if size would be less than minimum, it won't take effect const wxSize minSize = GetMinSize(); if (w >= minSize.x && h >= minSize.y) { gtk_window_resize(GTK_WINDOW(m_widget), w, h); resized = true; } } if (!resized) { // adjust overall size to match change in frame extents m_width += diff.x; m_height += diff.y; if (m_width < 0) m_width = 0; if (m_height < 0) m_height = 0; m_oldClientWidth = 0; gtk_widget_queue_resize(m_wxwindow); } } if (m_deferShow) { // gtk_widget_show() was deferred, do it now m_deferShow = false; GetClientSize(&m_oldClientWidth, &m_oldClientHeight); wxSizeEvent sizeEvent(GetSize(), GetId()); sizeEvent.SetEventObject(this); HandleWindowEvent(sizeEvent); gtk_widget_show(m_widget); wxShowEvent showEvent(GetId(), true); showEvent.SetEventObject(this); HandleWindowEvent(showEvent); } }
// Set the client size (i.e. leave the calculation of borders etc. // to wxWidgets) void wxFrame::DoSetClientSize(int width, int height) { // Calculate how large the new main window should be // by finding the difference between the client area and the // main window area, and adding on to the new client area if (width > -1) XtVaSetValues((Widget) m_workArea, XmNwidth, width, NULL); if (height > -1) { if (m_frameStatusBar) { int sbw, sbh; m_frameStatusBar->GetSize(& sbw, & sbh); height += sbh; } #if wxUSE_TOOLBAR if (m_frameToolBar) { int tbw, tbh; m_frameToolBar->GetSize(& tbw, & tbh); if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL) width += tbw; else height += tbh; } #endif // wxUSE_TOOLBAR XtVaSetValues((Widget) m_workArea, XmNheight, height, NULL); } PreResize(); wxSize newSize(width, height); wxSizeEvent sizeEvent(newSize, GetId()); sizeEvent.SetEventObject(this); GetEventHandler()->ProcessEvent(sizeEvent); }
bool wxApp::ProcessXEvent(WXEvent* _event) { XEvent* event = (XEvent*) _event; wxWindow* win = NULL; Window window = XEventGetWindow(event); #if 0 Window actualWindow = window; #endif // Find the first wxWindow that corresponds to this event window // Because we're receiving events after a window // has been destroyed, assume a 1:1 match between // Window and wxWindow, so if it's not in the table, // it must have been destroyed. win = wxGetWindowFromTable(window); if (!win) { #if wxUSE_TWO_WINDOWS win = wxGetClientWindowFromTable(window); if (!win) #endif return false; } switch (event->type) { case Expose: { #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX if (event->xexpose.window != (Window)win->GetClientAreaWindow()) { XEvent tmp_event; wxExposeInfo info; info.window = event->xexpose.window; info.found_non_matching = false; while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, wxX11ExposePredicate, (XPointer) &info )) { // Don't worry about optimizing redrawing the border etc. } win->NeedUpdateNcAreaInIdle(); } else #endif { win->GetUpdateRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), XExposeEventGetWidth(event), XExposeEventGetHeight(event)); win->GetClearRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), XExposeEventGetWidth(event), XExposeEventGetHeight(event)); #if !wxUSE_NANOX XEvent tmp_event; wxExposeInfo info; info.window = event->xexpose.window; info.found_non_matching = false; while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, wxX11ExposePredicate, (XPointer) &info )) { win->GetUpdateRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, tmp_event.xexpose.width, tmp_event.xexpose.height ); win->GetClearRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, tmp_event.xexpose.width, tmp_event.xexpose.height ); } #endif // This simplifies the expose and clear areas to simple // rectangles. win->GetUpdateRegion() = win->GetUpdateRegion().GetBox(); win->GetClearRegion() = win->GetClearRegion().GetBox(); // If we only have one X11 window, always indicate // that borders might have to be redrawn. if (win->X11GetMainWindow() == win->GetClientAreaWindow()) win->NeedUpdateNcAreaInIdle(); // Only erase background, paint in idle time. win->SendEraseEvents(); // EXPERIMENT //win->Update(); } return true; } #if !wxUSE_NANOX case GraphicsExpose: { wxLogTrace( wxT("expose"), wxT("GraphicsExpose from %s"), win->GetName().c_str()); win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, event->xgraphicsexpose.width, event->xgraphicsexpose.height); win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, event->xgraphicsexpose.width, event->xgraphicsexpose.height); if (event->xgraphicsexpose.count == 0) { // Only erase background, paint in idle time. win->SendEraseEvents(); // win->Update(); } return true; } #endif case KeyPress: { if (!win->IsEnabled()) return false; wxKeyEvent keyEvent(wxEVT_KEY_DOWN); wxTranslateKeyEvent(keyEvent, win, window, event); // wxLogDebug( "OnKey from %s", win->GetName().c_str() ); // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR if (win->HandleWindowEvent( keyEvent )) return true; keyEvent.SetEventType(wxEVT_CHAR); // Do the translation again, retaining the ASCII // code. if (wxTranslateKeyEvent(keyEvent, win, window, event, true) && win->HandleWindowEvent( keyEvent )) return true; if ( (keyEvent.m_keyCode == WXK_TAB) && win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { wxNavigationKeyEvent new_event; new_event.SetEventObject( win->GetParent() ); /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) ); /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ new_event.SetWindowChange( keyEvent.ControlDown() ); new_event.SetCurrentFocus( win ); return win->GetParent()->HandleWindowEvent( new_event ); } return false; } case KeyRelease: { if (!win->IsEnabled()) return false; wxKeyEvent keyEvent(wxEVT_KEY_UP); wxTranslateKeyEvent(keyEvent, win, window, event); return win->HandleWindowEvent( keyEvent ); } case ConfigureNotify: { #if wxUSE_NANOX if (event->update.utype == GR_UPDATE_SIZE) #endif { wxTopLevelWindow *tlw = wxDynamicCast(win, wxTopLevelWindow); if ( tlw ) { tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event), XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) ); } if ( tlw && tlw->IsShown() ) { tlw->SetNeedResizeInIdle(); } else { wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() ); sizeEvent.SetEventObject( win ); return win->HandleWindowEvent( sizeEvent ); } } return false; } #if !wxUSE_NANOX case PropertyNotify: return HandlePropertyChange(_event); case ClientMessage: { if (!win->IsEnabled()) return false; Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True); Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True); if (event->xclient.message_type == wm_protocols) { if ((Atom) (event->xclient.data.l[0]) == wm_delete_window) { win->Close(false); return true; } } return false; } #if 0 case DestroyNotify: { printf( "destroy from %s\n", win->GetName().c_str() ); break; } case CreateNotify: { printf( "create from %s\n", win->GetName().c_str() ); break; } case MapRequest: { printf( "map request from %s\n", win->GetName().c_str() ); break; } case ResizeRequest: { printf( "resize request from %s\n", win->GetName().c_str() ); Display *disp = (Display*) wxGetDisplay(); XEvent report; // to avoid flicker report = * event; while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report)); wxSize sz = win->GetSize(); wxSizeEvent sizeEvent(sz, win->GetId()); sizeEvent.SetEventObject(win); return win->HandleWindowEvent( sizeEvent ); } #endif #endif #if wxUSE_NANOX case GR_EVENT_TYPE_CLOSE_REQ: { if (win) { win->Close(false); return true; } return false; break; } #endif case EnterNotify: case LeaveNotify: case ButtonPress: case ButtonRelease: case MotionNotify: { if (!win->IsEnabled()) return false; // Here we check if the top level window is // disabled, which is one aspect of modality. wxWindow *tlw = win; while (tlw && !tlw->IsTopLevel()) tlw = tlw->GetParent(); if (tlw && !tlw->IsEnabled()) return false; if (event->type == ButtonPress) { if ((win != wxWindow::FindFocus()) && win->CanAcceptFocus()) { // This might actually be done in wxWindow::SetFocus() // and not here. TODO. g_prevFocus = wxWindow::FindFocus(); g_nextFocus = win; wxLogTrace( wxT("focus"), wxT("About to call SetFocus on %s of type %s due to button press"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); // Record the fact that this window is // getting the focus, because we'll need to // check if its parent is getting a bogus // focus and duly ignore it. // TODO: may need to have this code in SetFocus, too. extern wxWindow* g_GettingFocus; g_GettingFocus = win; win->SetFocus(); } } #if !wxUSE_NANOX if (event->type == LeaveNotify || event->type == EnterNotify) { // Throw out NotifyGrab and NotifyUngrab if (event->xcrossing.mode != NotifyNormal) return false; } #endif wxMouseEvent wxevent; wxTranslateMouseEvent(wxevent, win, window, event); return win->HandleWindowEvent( wxevent ); } case FocusIn: #if !wxUSE_NANOX if ((event->xfocus.detail != NotifyPointer) && (event->xfocus.mode == NotifyNormal)) #endif { wxLogTrace( wxT("focus"), wxT("FocusIn from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); extern wxWindow* g_GettingFocus; if (g_GettingFocus && g_GettingFocus->GetParent() == win) { // Ignore this, this can be a spurious FocusIn // caused by a child having its focus set. g_GettingFocus = NULL; wxLogTrace( wxT("focus"), wxT("FocusIn from %s of type %s being deliberately ignored"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); return true; } else { wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId()); focusEvent.SetEventObject(win); focusEvent.SetWindow( g_prevFocus ); g_prevFocus = NULL; return win->HandleWindowEvent(focusEvent); } } return false; case FocusOut: #if !wxUSE_NANOX if ((event->xfocus.detail != NotifyPointer) && (event->xfocus.mode == NotifyNormal)) #endif { wxLogTrace( wxT("focus"), wxT("FocusOut from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId()); focusEvent.SetEventObject(win); focusEvent.SetWindow( g_nextFocus ); g_nextFocus = NULL; return win->HandleWindowEvent(focusEvent); } return false; } return false; }
void X11AppContext::processEvent(const x11::GenericEvent& ev) { //macro for easier event creation for registered EventHandler #define EventHandlerEvent(T, W) \ auto handler = eventHandler(W); \ if(!handler) return; \ auto event = T(handler); auto dispatch = [&](Event& event){ if(event.handler) event.handler->handleEvent(event); }; auto responseType = ev.response_type & ~0x80; switch(responseType) { case XCB_MOTION_NOTIFY: { auto& motion = reinterpret_cast<const xcb_motion_notify_event_t&>(ev); auto pos = nytl::Vec2i(motion.event_x, motion.event_y); mouseContext_->move(pos); EventHandlerEvent(MouseMoveEvent, motion.event); event.position = pos; event.screenPosition = nytl::Vec2i(motion.root_x, motion.root_y); dispatch(event); break; } case XCB_EXPOSE: { auto& expose = reinterpret_cast<const xcb_expose_event_t&>(ev); if(expose.count == 0) { EventHandlerEvent(DrawEvent, expose.window); dispatch(event); } break; } case XCB_MAP_NOTIFY: { auto& map = reinterpret_cast<const xcb_map_notify_event_t&>(ev); EventHandlerEvent(DrawEvent, map.window); dispatch(event); break; } case XCB_BUTTON_PRESS: { auto& button = reinterpret_cast<const xcb_button_press_event_t&>(ev); int scroll = 0; if(button.detail == 4) scroll = 1; else if(button.detail == 5) scroll = -1; if(scroll) { EventHandlerEvent(MouseWheelEvent, button.event); event.data = std::make_unique<X11EventData>(ev); event.value = scroll; mouseContext_->onWheel(*mouseContext_, scroll); dispatch(event); break; } auto b = x11ToButton(button.detail); mouseContext_->mouseButton(b, true); EventHandlerEvent(MouseButtonEvent, button.event); event.data = std::make_unique<X11EventData>(ev); event.button = b; event.position = nytl::Vec2i(button.event_x, button.event_y); event.pressed = true; dispatch(event); break; } case XCB_BUTTON_RELEASE: { auto& button = reinterpret_cast<const xcb_button_release_event_t&>(ev); if(button.detail == 4 || button.detail == 5) break; auto b = x11ToButton(button.detail); mouseContext_->mouseButton(b, false); EventHandlerEvent(MouseButtonEvent, button.event); event.data = std::make_unique<X11EventData>(ev); event.button = b; event.position = nytl::Vec2i(button.event_x, button.event_y); event.pressed = false; dispatch(event); break; } case XCB_ENTER_NOTIFY: { auto& enter = reinterpret_cast<const xcb_enter_notify_event_t&>(ev); auto wc = windowContext(enter.event); mouseContext_->over(wc); EventHandlerEvent(MouseCrossEvent, enter.event); event.position = nytl::Vec2i(enter.event_x, enter.event_y); event.entered = true; dispatch(event); break; } case XCB_LEAVE_NOTIFY: { auto& leave = reinterpret_cast<const xcb_enter_notify_event_t&>(ev); auto wc = windowContext(leave.event); if(mouseContext_->over() == wc) mouseContext_->over(nullptr); EventHandlerEvent(MouseCrossEvent, leave.event); event.position = nytl::Vec2i(leave.event_x, leave.event_y); event.entered = false; dispatch(event); break; } case XCB_FOCUS_IN: { auto& focus = reinterpret_cast<const xcb_focus_in_event_t&>(ev); auto wc = windowContext(focus.event); keyboardContext_->focus(wc); EventHandlerEvent(FocusEvent, focus.event); event.focus = true; dispatch(event); break; } case XCB_FOCUS_OUT: { auto& focus = reinterpret_cast<const xcb_focus_in_event_t&>(ev); auto wc = windowContext(focus.event); if(keyboardContext_->focus() == wc)keyboardContext_->focus(nullptr); EventHandlerEvent(FocusEvent, focus.event); event.focus = false; dispatch(event); break; } case XCB_KEY_PRESS: { auto& key = reinterpret_cast<const xcb_key_press_event_t&>(ev); EventHandlerEvent(KeyEvent, key.event); event.pressed = true; if(!keyboardContext_->keyEvent(key.detail, event)) bell(); dispatch(event); break; } case XCB_KEY_RELEASE: { auto& key = reinterpret_cast<const xcb_key_press_event_t&>(ev); EventHandlerEvent(KeyEvent, key.event); event.pressed = false; if(!keyboardContext_->keyEvent(key.detail, event)) bell(); dispatch(event); break; } case XCB_REPARENT_NOTIFY: { auto& reparent = reinterpret_cast<const xcb_reparent_notify_event_t&>(ev); auto wc = windowContext(reparent.window); if(wc) wc->reparentEvent(); break; } case XCB_CONFIGURE_NOTIFY: { auto& configure = reinterpret_cast<const xcb_configure_notify_event_t&>(ev); //todo: something about window state auto nsize = nytl::Vec2ui(configure.width, configure.height); // auto npos = nytl::Vec2i(configure.x, configure.y); //positionEvent auto wc = windowContext(configure.window); if(wc) wc->sizeEvent(nsize); if(!eventHandler(configure.window)) break; /* TODO XXX !important if(any(windowContext(configure.window)->window().size() != nsize)) //sizeEvent { EventHandlerEvent(SizeEvent, configure.window); event->size = nsize; event->change = 0; dispatcher.dispatch(std::move(event)); auto wc = windowContext(configure.window); if(!wc) return true; auto wevent = std::make_unique<SizeEvent>(wc); wevent->size = nsize; wevent->change = 0; dispatcher.dispatch(std::move(wevent)); } if(any(windowContext(configure.window)->window().position() != npos)) { EventHandlerEvent(PositionEvent, configure.window); event->position = npos; event->change = 0; dispatcher.dispatch(std::move(event)); } */ break; } case XCB_CLIENT_MESSAGE: { auto& client = reinterpret_cast<const xcb_client_message_event_t&>(ev); auto protocol = static_cast<unsigned int>(client.data.data32[0]); if(protocol == atoms().wmDeleteWindow) { EventHandlerEvent(CloseEvent, client.window); dispatch(event); } break; } case 0u: { //an error occurred! int code = reinterpret_cast<const xcb_generic_error_t&>(ev).error_code; auto errorMsg = x11::errorMessage(xDisplay(), code); warning("ny::X11AppContext::processEvent: retrieved error code ", code, ", ", errorMsg); break; } default: { //check for xkb event if(ev.response_type == keyboardContext_->xkbEventType()) keyboardContext_->processXkbEvent(ev); // May be needed for gl to work correctly... (TODO: test) // XLockDisplay(xDisplay_); // auto proc = XESetWireToEvent(xDisplay_, ev.response_type & ~0x80, nullptr); // if(proc) // { // XESetWireToEvent(xDisplay_, ev.response_type & ~0x80, proc); // XEvent dummy; // ev.sequence = LastKnownRequestProcessed(xDisplay_); // if(proc(xDisplay_, &dummy, (xEvent*) &ev)) //not handled // { // //TODO // } // } // // XUnlockDisplay(xDisplay_); } } #undef EventHandlerEvent }
bool wxFrame::Create(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) { if( !wxTopLevelWindow::Create( parent, id, title, pos, size, style, name ) ) return false; m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); m_foregroundColour = *wxBLACK; m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); int x = pos.x, y = pos.y; int width = size.x, height = size.y; // Set reasonable values for position and size if defaults have been // requested // // MB TODO: something better than these arbitrary values ? // VZ should use X resources for this... if ( width == -1 ) width = 400; if ( height == -1 ) height = 400; int displayW, displayH; wxDisplaySize( &displayW, &displayH ); if ( x == -1 ) { x = (displayW - width) / 2; if (x < 10) x = 10; } if ( y == -1 ) { y = (displayH - height) / 2; if (y < 10) y = 10; } SetTitle( title ); wxLogTrace(wxTRACE_Messages, "Created frame (0x%p) with work area 0x%p and client " "area 0x%p", m_mainWidget, m_workArea, m_clientArea); XtAddEventHandler((Widget) m_clientArea, ExposureMask,False, wxUniversalRepaintProc, (XtPointer) this); if (x > -1) XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL); if (y > -1) XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL); if (width > -1) XtVaSetValues((Widget) m_frameShell, XmNwidth, width, NULL); if (height > -1) XtVaSetValues((Widget) m_frameShell, XmNheight, height, NULL); ChangeFont(false); ChangeBackgroundColour(); PreResize(); wxSize newSize(width, height); wxSizeEvent sizeEvent(newSize, GetId()); sizeEvent.SetEventObject(this); GetEventHandler()->ProcessEvent(sizeEvent); return true; }