def set_video_mode(self, w, h, d): if not (w > 0 and h > 0): return assert d in (1, 2, 4, 8, 16, 32) if d < MINIMUM_DEPTH: d = BELOW_MINIMUM_DEPTH self.width = intmask(w) self.height = intmask(h) self.depth = intmask(d) if self.window == lltype.nullptr(RSDL.WindowPtr.TO): self.create_window_and_renderer(x=RSDL.WINDOWPOS_UNDEFINED, y=RSDL.WINDOWPOS_UNDEFINED, width=w, height=h) if self.screen_texture != lltype.nullptr(RSDL.TexturePtr.TO): RSDL.DestroyTexture(self.screen_texture) self.screen_texture = RSDL.CreateTexture(self.renderer, DEPTH_TO_PIXELFORMAT[d], RSDL.TEXTUREACCESS_STREAMING, w, h) if not self.screen_texture: print 'Could not create screen texture' raise RuntimeError(RSDL.GetError()) self.lock() if d == 16: self.bpp = 2 elif d == 32: self.bpp = 4 else: assert False self.pitch = self.width * self.bpp self.full_damage()
def create_window_and_renderer(self, x, y, width, height): flags = RSDL.WINDOW_RESIZABLE if self.highdpi: flags |= RSDL.WINDOW_ALLOW_HIGHDPI self.window = RSDL.CreateWindow(self.title, x, y, width, height, flags) # Use software renderer for now to avoid problems w/ duplicate buffers self.renderer = RSDL.CreateRenderer(self.window, -1, RSDL.RENDERER_SOFTWARE)
def create_screen(self): # 32 bits per pixel # 0 no flags self.screen = RSDL.SetVideoMode(self.width * self.scale, self.height * self.scale, 32, 0) fmt = self.screen.c_format self.colors = [] for color in self.COLOR_MAP: color = RSDL.MapRGB(fmt, *color) self.colors.append(color) self.blit_rect = RSDL_helper.mallocrect(0, 0, self.scale, self.scale)
def get_modifier_mask(self, shift): RSDL.PumpEvents() mod = RSDL.GetModState() modifier = 0 if mod & RSDL.KMOD_CTRL != 0: modifier |= CtrlKeyBit if mod & RSDL.KMOD_SHIFT != 0: modifier |= ShiftKeyBit if mod & RSDL.KMOD_ALT != 0: modifier |= (OptionKeyBit | CommandKeyBit) return modifier << shift
def __init__(self, title): assert RSDL.Init(RSDL.INIT_VIDEO) >= 0 RSDL.WM_SetCaption(title, "RSqueakVM") RSDL.EnableUNICODE(1) SDLCursor.has_display = True self.has_surface = False self.mouse_position = [0, 0] self.interrupt_key = 15 << 8 # pushing all four meta keys, of which we support three... self.button = 0 self.key = 0 self._deferred_event = None self._defer_updates = False
def get_next_event(self, time=0): if self._deferred_event: deferred = self._deferred_event self._deferred_event = None return deferred event = lltype.malloc(RSDL.Event, flavor="raw") try: if rffi.cast(lltype.Signed, RSDL.PollEvent(event)) == 1: c_type = rffi.getintfield(event, 'c_type') if c_type in [RSDL.MOUSEBUTTONDOWN, RSDL.MOUSEBUTTONUP]: self.handle_mouse_button(c_type, event) return self.get_next_mouse_event(time) elif c_type == RSDL.MOUSEMOTION: self.handle_mouse_move(c_type, event) return self.get_next_mouse_event(time) elif c_type == RSDL.KEYDOWN: self.handle_keypress(c_type, event) return self.get_next_key_event(EventKeyDown, time) elif c_type == RSDL.KEYUP: self._deferred_event = self.get_next_key_event( EventKeyUp, time) return self.get_next_key_event(EventKeyChar, time) elif c_type == RSDL.VIDEORESIZE: self.screen = RSDL.GetVideoSurface() self._deferred_event = [ EventTypeWindow, time, WindowEventPaint, 0, 0, int(self.screen.c_w), int(self.screen.c_h), 0 ] return [ EventTypeWindow, time, WindowEventMetricChange, 0, 0, int(self.screen.c_w), int(self.screen.c_h), 0 ] elif c_type == RSDL.VIDEOEXPOSE: self._deferred_event = [ EventTypeWindow, time, WindowEventPaint, 0, 0, int(self.screen.c_w), int(self.screen.c_h), 0 ] return [ EventTypeWindow, time, WindowEventActivated, 0, 0, 0, 0, 0 ] elif c_type == RSDL.QUIT: return [ EventTypeWindow, time, WindowEventClose, 0, 0, 0, 0, 0 ] finally: lltype.free(event, flavor='raw') return [EventTypeNone, 0, 0, 0, 0, 0, 0, 0]
def render(self, force=False): if not force: if self._defer_updates or not self._texture_dirty: return self._texture_dirty = False self.unlock() ec = RSDL.RenderCopy(self.renderer, self.screen_texture, RENDER_RECT, RENDER_RECT) if ec != 0: print RSDL.GetError() return RSDL.RenderPresent(self.renderer) self.reset_damage() self.lock()
def set(self, data_words, w, h, x, y, mask_words=None): if not self.has_display: return if self.has_cursor: RSDL.FreeCursor(self.cursor) data = self.words_to_bytes(len(data_words) * 4, data_words) try: mask = self.words_to_bytes(len(data_words) * 4, mask_words) try: self.cursor = RSDL.CreateCursor(data, mask, w * 2, h, x, y) self.has_cursor = True RSDL.SetCursor(self.cursor) finally: lltype.free(mask, flavor="raw") finally: lltype.free(data, flavor="raw")
def draw_pixel(self, x, y, color): color = self.colors[color] start_x = x * self.scale start_y = y * self.scale dstrect = self.blit_rect rffi.setintfield(dstrect, 'c_x', start_x) rffi.setintfield(dstrect, 'c_y', start_y) RSDL.FillRect(self.screen, dstrect, color)
def get_modifier_mask(self, shift): RSDL.PumpEvents() mod = RSDL.GetModState() modifier = 0 if mod & RSDL.KMOD_CTRL != 0: modifier |= CtrlKeyBit if mod & RSDL.KMOD_SHIFT != 0: modifier |= ShiftKeyBit if mod & RSDL.KMOD_CAPS != 0: modifier |= ShiftKeyBit if mod & RSDL.KMOD_ALT != 0: if not system.IS_DARWIN: modifier |= CommandKeyBit else: modifier |= OptionKeyBit if mod & RSDL.KMOD_GUI != 0: modifier |= CommandKeyBit return intmask(modifier << shift)
def set(self, data_words, w, h, x, y, mask_words=None): if not self.has_display: return True if self.has_cursor: RSDL.FreeCursor(self.cursor) bytenum = len(data_words) * 2 data = self.cursor_words_to_bytes(bytenum, data_words) try: mask = self.cursor_words_to_bytes(bytenum, mask_words) try: self.cursor = RSDL.CreateCursor(data, mask, w, h, x, y) if self.cursor == lltype.nullptr(RSDL.CursorPtr.TO): print RSDL.GetError() return False self.has_cursor = True RSDL.SetCursor(self.cursor) finally: lltype.free(mask, flavor='raw') finally: lltype.free(data, flavor='raw') return True
def _init_sdl(self): if RSDL.Init(RSDL.INIT_VIDEO) < 0: print RSDL.GetError() assert False self.interrupt_flag = lltype.malloc(rffi.SIGNEDP.TO, 1, flavor='raw') self.interrupt_flag[0] = 0 ll_SetEventFilter(self.interrupt_flag) # do not wait for vsync RSDL.SetHint(RSDL.HINT_RENDER_VSYNC, '0') # nearest pixel sampling RSDL.SetHint(RSDL.HINT_RENDER_SCALE_QUALITY, '0') # disable WM_PING, so the WM does not think we're hung RSDL.SetHint(RSDL.HINT_VIDEO_X11_NET_WM_PING, '0') # Ctrl-Click on Mac is right click RSDL.SetHint(RSDL.HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, '1') for eventname in DISABLED_EVENTS: RSDL.EventState(getattr(RSDL, eventname), RSDL.IGNORE) # try to allow late tearing (pushes frames faster) if (RSDL.SetSwapInterval(-1) < 0): RSDL.SetSwapInterval(0) # at least try to disable vsync
def set_squeak_colormap(self, screen): # TODO: fix this up from the image colors = lltype.malloc(rffi.CArray(RSDL.ColorPtr.TO), 4, flavor='raw') colors[0].c_r = rffi.r_uchar(255) colors[0].c_g = rffi.r_uchar(255) colors[0].c_b = rffi.r_uchar(255) colors[1].c_r = rffi.r_uchar(0) colors[1].c_g = rffi.r_uchar(0) colors[1].c_b = rffi.r_uchar(0) colors[2].c_r = rffi.r_uchar(128) colors[2].c_g = rffi.r_uchar(128) colors[2].c_b = rffi.r_uchar(128) colors[3].c_r = rffi.r_uchar(255) colors[3].c_g = rffi.r_uchar(255) colors[3].c_b = rffi.r_uchar(255) RSDL.SetColors(self.screen, rffi.cast(RSDL.ColorPtr, colors), 0, 4) lltype.free(colors, flavor='raw')
def set_video_mode(self, w, h, d): assert w > 0 and h > 0 assert d in [1, 2, 4, 8, 16, 32] if d < MINIMUM_DEPTH: d = MINIMUM_DEPTH self.width = w self.height = h self.depth = d flags = RSDL.HWPALETTE | RSDL.RESIZABLE | RSDL.ASYNCBLIT | RSDL.DOUBLEBUF self.screen = RSDL.SetVideoMode(w, h, d, flags) if not self.screen: print "Could not open display at depth %d" % d raise RuntimeError elif d == MINIMUM_DEPTH: self.set_squeak_colormap(self.screen) self.bpp = rffi.getintfield(self.screen.c_format, 'c_BytesPerPixel') self.pitch = rffi.getintfield(self.screen, 'c_pitch')
def pump_events(self): event = lltype.malloc(RSDL.Event, flavor="raw") try: if rffi.cast(lltype.Signed, RSDL.PollEvent(event)) == 1: c_type = rffi.getintfield(event, 'c_type') if c_type == RSDL.MOUSEBUTTONDOWN or c_type == RSDL.MOUSEBUTTONUP: self.handle_mouse_button(c_type, event) return elif c_type == RSDL.MOUSEMOTION: self.handle_mouse_move(c_type, event) elif c_type == RSDL.KEYDOWN: self.handle_keypress(c_type, event) return elif c_type == RSDL.QUIT: from spyvm.error import Exit raise Exit("Window closed") finally: lltype.free(event, flavor='raw')
def pump_events(self): event = lltype.malloc(RSDL.Event, flavor='raw') try: if RSDL.PollEvent(event) == 1: c_type = r_uint(event.c_type) if (c_type == r_uint(RSDL.MOUSEBUTTONDOWN) or c_type == r_uint(RSDL.MOUSEBUTTONUP)): self.handle_mouse_button(c_type, event) return elif c_type == r_uint(RSDL.MOUSEMOTION): self.handle_mouse_move(c_type, event) elif c_type == r_uint(RSDL.KEYDOWN): self.handle_keyboard_event(c_type, event) return elif c_type == r_uint(RSDL.QUIT): from rsqueakvm.error import Exit raise Exit('Window closed') finally: lltype.free(event, flavor='raw')
def get_next_event(self, time=0): if self.has_queued_events(): return self.dequeue_event() got_event = False with lltype.scoped_alloc(RSDL.Event) as event: while RSDL.PollEvent(event) == 1: got_event = True event_type = r_uint(event.c_type) if event_type in (RSDL.MOUSEBUTTONDOWN, RSDL.MOUSEBUTTONUP): self.handle_mouse_button(event_type, event) self.queue_event(self.get_next_mouse_event(time)) elif event_type == RSDL.MOUSEMOTION: self.handle_mouse_move(event_type, event) self.queue_event(self.get_next_mouse_event(time)) elif event_type == RSDL.MOUSEWHEEL: self.queue_event( self.get_next_mouse_wheel_event(time, event)) elif event_type == RSDL.KEYDOWN: self.handle_keyboard_event(event_type, event) later = None if not self.is_modifier_key(self.key): # no TEXTINPUT event for this key will follow, but # Squeak needs a KeyStroke anyway if ((system.IS_LINUX and self.is_control_key(self.key)) or (not system.IS_LINUX and (self.is_control_key(self.key) or RSDL.GetModState() & ~RSDL.KMOD_SHIFT != 0))): later = self.get_next_key_event(EventKeyChar, time) self.fix_key_code_case() self.queue_event( self.get_next_key_event(EventKeyDown, time)) if later: self.insert_padding_event() self.queue_event(later) elif event_type == RSDL.TEXTINPUT: self.handle_textinput_event(event) self.queue_event( self.get_next_key_event(EventKeyChar, time)) elif event_type == RSDL.KEYUP: self.handle_keyboard_event(event_type, event) self.fix_key_code_case() self.queue_event(self.get_next_key_event(EventKeyUp, time)) elif event_type == RSDL.WINDOWEVENT: self.handle_windowevent(event_type, event) elif event_type == RSDL.DROPFILE: self.queue_event( self.get_dropevent(time, event_type, event)) elif event_type == RSDL.QUIT: if self.altf4quit: # we want to quit hard from rsqueakvm.util.dialog import ask_question if ask_question('Quit Squeak without saving?'): raise Exception self.queue_event([ EventTypeWindow, time, WindowEventClose, 0, 0, 0, 0, 0 ]) elif event_type in (RSDL.RENDER_TARGETS_RESET, RSDL.RENDER_DEVICE_RESET): self.full_damage() self.render(force=True) self.insert_padding_event() if got_event: return self.dequeue_event() return [EventTypeNone, 0, 0, 0, 0, 0, 0, 0]
def unlock(self): RSDL.UnlockTexture(self.screen_texture)
def lock(self): ec = RSDL.LockTexture(self.screen_texture, lltype.nullptr(RSDL.Rect), PIXELVOIDPP, PITCHINTP) if ec != 0: print RSDL.GetError() return
def record_damage(self, x, y, w, h): FLIP_RECT.c_x = rffi.r_int(x) FLIP_RECT.c_y = rffi.r_int(y) FLIP_RECT.c_w = rffi.r_int(min(w + 1, self.width - x)) FLIP_RECT.c_h = rffi.r_int(min(h + 1, self.height - y)) RSDL.UnionRect(FLIP_RECT, RENDER_RECT, RENDER_RECT)
def set_title(self, title): RSDL.SetWindowTitle(self.window, title)
def set_full_screen(self, flag): if flag: RSDL.SetWindowFullscreen(self.window, RSDL.WINDOW_FULLSCREEN_DESKTOP) else: RSDL.SetWindowFullscreen(self.window, 0)
def has_clipboard_text(self): return RSDL.HasClipboardText() == RSDL.TRUE
def close(self): RSDL.Quit()
def get_clipboard_text(self): return rffi.charp2str(RSDL.GetClipboardText())
def __del__(self): # Close the display. RSDL.Quit()
def set_clipboard_text(self, text): return RSDL.SetClipboardText(rffi.str2charp(text))
def flip(self, force=False): if (not self._defer_updates) or force: RSDL.Flip(self.screen)
def handle_execution_error(self, error): lltype.free(self.event, flavor='raw') RSDL.Quit()
def poll_event(self): ok = rffi.cast(lltype.Signed, RSDL.PollEvent(self.event)) return ok > 0