diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 04f6802a..1caa6d4d 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -125,103 +125,6 @@ impl Window2 { win }; - // Enable drag and drop - unsafe { - let atom_name: *const libc::c_char = b"XdndAware\0".as_ptr() as _; - let atom = (display.xlib.XInternAtom)(display.display, atom_name, ffi::False); - let version = &5; // Latest version; hasn't changed since 2002 - (display.xlib.XChangeProperty)( - display.display, - window, - atom, - ffi::XA_ATOM, - 32, - ffi::PropModeReplace, - version, - 1 - ); - display.check_errors().expect("Failed to set drag and drop properties"); - } - - // Set ICCCM WM_CLASS property based on initial window title - // Must be done *before* mapping the window by ICCCM 4.1.2.5 - unsafe { - with_c_str(&*window_attrs.title, |c_name| { - let hint = (display.xlib.XAllocClassHint)(); - (*hint).res_name = c_name as *mut libc::c_char; - (*hint).res_class = c_name as *mut libc::c_char; - (display.xlib.XSetClassHint)(display.display, window, hint); - display.check_errors().expect("Failed to call XSetClassHint"); - (display.xlib.XFree)(hint as *mut _); - }); - } - - // set visibility - if window_attrs.visible { - unsafe { - (display.xlib.XMapRaised)(display.display, window); - (display.xlib.XFlush)(display.display); - } - - display.check_errors().expect("Failed to set window visibility"); - } - - // Opt into handling window close - unsafe { - (display.xlib.XSetWMProtocols)(display.display, window, &ctx.wm_delete_window as *const _ as *mut _, 1); - display.check_errors().expect("Failed to call XSetWMProtocols"); - (display.xlib.XFlush)(display.display); - display.check_errors().expect("Failed to call XFlush"); - } - - // Attempt to make keyboard input repeat detectable - unsafe { - let mut supported_ptr = ffi::False; - (display.xlib.XkbSetDetectableAutoRepeat)(display.display, ffi::True, &mut supported_ptr); - if supported_ptr == ffi::False { - return Err(OsError(format!("XkbSetDetectableAutoRepeat failed"))); - } - } - - // set size hints - let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() }; - size_hints.flags = ffi::PSize; - size_hints.width = dimensions.0 as i32; - size_hints.height = dimensions.1 as i32; - if let Some(dimensions) = window_attrs.min_dimensions { - size_hints.flags |= ffi::PMinSize; - size_hints.min_width = dimensions.0 as i32; - size_hints.min_height = dimensions.1 as i32; - } - if let Some(dimensions) = window_attrs.max_dimensions { - size_hints.flags |= ffi::PMaxSize; - size_hints.max_width = dimensions.0 as i32; - size_hints.max_height = dimensions.1 as i32; - } - unsafe { - (display.xlib.XSetNormalHints)(display.display, window, &mut size_hints); - display.check_errors().expect("Failed to call XSetNormalHints"); - } - - // Select XInput2 events - { - let mask = ffi::XI_MotionMask - | ffi::XI_ButtonPressMask | ffi::XI_ButtonReleaseMask - // | ffi::XI_KeyPressMask | ffi::XI_KeyReleaseMask - | ffi::XI_EnterMask | ffi::XI_LeaveMask - | ffi::XI_FocusInMask | ffi::XI_FocusOutMask - | if window_attrs.multitouch { ffi::XI_TouchBeginMask | ffi::XI_TouchUpdateMask | ffi::XI_TouchEndMask } else { 0 }; - unsafe { - let mut event_mask = ffi::XIEventMask{ - deviceid: ffi::XIAllMasterDevices, - mask: mem::transmute::<*const i32, *mut c_uchar>(&mask as *const i32), - mask_len: mem::size_of_val(&mask) as c_int, - }; - (display.xinput2.XISelectEvents)(display.display, window, - &mut event_mask as *mut ffi::XIEventMask, 1); - }; - } - let window = Window2 { x: Arc::new(XWindow { display: display.clone(), @@ -232,35 +135,138 @@ impl Window2 { cursor_state: Mutex::new(CursorState::Normal), }; + // Title must be set before mapping, lest some tiling window managers briefly pick up on + // the initial un-titled window state window.set_title(&window_attrs.title); window.set_decorations(window_attrs.decorations); - window.set_maximized(window_attrs.maximized); - window.set_fullscreen(window_attrs.fullscreen.clone()); - if window_attrs.visible { + { + let ref x_window: &XWindow = window.x.borrow(); + + // Enable drag and drop unsafe { - let ref x_window: &XWindow = window.x.borrow(); + let atom_name: *const libc::c_char = b"XdndAware\0".as_ptr() as _; + let atom = (display.xlib.XInternAtom)(display.display, atom_name, ffi::False); + let version = &5; // Latest version; hasn't changed since 2002 + (display.xlib.XChangeProperty)( + display.display, + x_window.window, + atom, + ffi::XA_ATOM, + 32, + ffi::PropModeReplace, + version, + 1 + ); + display.check_errors().expect("Failed to set drag and drop properties"); + } - // XSetInputFocus generates an error if the window is not visible, - // therefore we wait until it's the case. - loop { - let mut window_attributes = mem::uninitialized(); - (display.xlib.XGetWindowAttributes)(display.display, x_window.window, &mut window_attributes); - display.check_errors().expect("Failed to call XGetWindowAttributes"); + // Set ICCCM WM_CLASS property based on initial window title + // Must be done *before* mapping the window by ICCCM 4.1.2.5 + unsafe { + with_c_str(&*window_attrs.title, |c_name| { + let hint = (display.xlib.XAllocClassHint)(); + (*hint).res_name = c_name as *mut libc::c_char; + (*hint).res_class = c_name as *mut libc::c_char; + (display.xlib.XSetClassHint)(display.display, x_window.window, hint); + display.check_errors().expect("Failed to call XSetClassHint"); + (display.xlib.XFree)(hint as *mut _); + }); + } - if window_attributes.map_state == ffi::IsViewable { - (display.xlib.XSetInputFocus)( - display.display, - x_window.window, - ffi::RevertToParent, - ffi::CurrentTime - ); - display.check_errors().expect("Failed to call XSetInputFocus"); - break; + // set size hints + let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() }; + size_hints.flags = ffi::PSize; + size_hints.width = dimensions.0 as i32; + size_hints.height = dimensions.1 as i32; + if let Some(dimensions) = window_attrs.min_dimensions { + size_hints.flags |= ffi::PMinSize; + size_hints.min_width = dimensions.0 as i32; + size_hints.min_height = dimensions.1 as i32; + } + if let Some(dimensions) = window_attrs.max_dimensions { + size_hints.flags |= ffi::PMaxSize; + size_hints.max_width = dimensions.0 as i32; + size_hints.max_height = dimensions.1 as i32; + } + unsafe { + (display.xlib.XSetNormalHints)(display.display, x_window.window, &mut size_hints); + display.check_errors().expect("Failed to call XSetNormalHints"); + } + + // Opt into handling window close + unsafe { + (display.xlib.XSetWMProtocols)(display.display, x_window.window, &ctx.wm_delete_window as *const _ as *mut _, 1); + display.check_errors().expect("Failed to call XSetWMProtocols"); + (display.xlib.XFlush)(display.display); + display.check_errors().expect("Failed to call XFlush"); + } + + // Set visibility (map window) + if window_attrs.visible { + unsafe { + (display.xlib.XMapRaised)(display.display, x_window.window); + (display.xlib.XFlush)(display.display); + } + + display.check_errors().expect("Failed to set window visibility"); + } + + // Attempt to make keyboard input repeat detectable + unsafe { + let mut supported_ptr = ffi::False; + (display.xlib.XkbSetDetectableAutoRepeat)(display.display, ffi::True, &mut supported_ptr); + if supported_ptr == ffi::False { + return Err(OsError(format!("XkbSetDetectableAutoRepeat failed"))); + } + } + + // Select XInput2 events + { + let mask = ffi::XI_MotionMask + | ffi::XI_ButtonPressMask | ffi::XI_ButtonReleaseMask + // | ffi::XI_KeyPressMask | ffi::XI_KeyReleaseMask + | ffi::XI_EnterMask | ffi::XI_LeaveMask + | ffi::XI_FocusInMask | ffi::XI_FocusOutMask + | if window_attrs.multitouch { ffi::XI_TouchBeginMask | ffi::XI_TouchUpdateMask | ffi::XI_TouchEndMask } else { 0 }; + unsafe { + let mut event_mask = ffi::XIEventMask{ + deviceid: ffi::XIAllMasterDevices, + mask: mem::transmute::<*const i32, *mut c_uchar>(&mask as *const i32), + mask_len: mem::size_of_val(&mask) as c_int, + }; + (display.xinput2.XISelectEvents)(display.display, x_window.window, + &mut event_mask as *mut ffi::XIEventMask, 1); + }; + } + + // These properties must be set after mapping + window.set_maximized(window_attrs.maximized); + window.set_fullscreen(window_attrs.fullscreen.clone()); + + if window_attrs.visible { + unsafe { + // XSetInputFocus generates an error if the window is not visible, + // therefore we wait until it's the case. + loop { + let mut window_attributes = mem::uninitialized(); + (display.xlib.XGetWindowAttributes)(display.display, x_window.window, &mut window_attributes); + display.check_errors().expect("Failed to call XGetWindowAttributes"); + + if window_attributes.map_state == ffi::IsViewable { + (display.xlib.XSetInputFocus)( + display.display, + x_window.window, + ffi::RevertToParent, + ffi::CurrentTime + ); + display.check_errors().expect("Failed to call XSetInputFocus"); + break; + } + + // Wait about a frame to avoid too-busy waiting + thread::sleep(Duration::from_millis(16)); } - - // Wait about a frame to avoid too-busy waiting - thread::sleep(Duration::from_millis(16)); } } }