mirror of https://github.com/kivy/kivy.git
core/window: better handling of system size. window size can now be changed, opengl is automatically reloaded on the first resize (the first initialization doesn't count.)
+ fix issue with mouse_up never fired after a resize
This commit is contained in:
parent
d05777e954
commit
d45219d5b8
|
@ -12,13 +12,14 @@ from os.path import join, exists
|
|||
from os import getcwd
|
||||
|
||||
from kivy.core import core_select_lib
|
||||
from kivy.clock import Clock
|
||||
from kivy.config import Config
|
||||
from kivy.logger import Logger
|
||||
from kivy.base import EventLoop
|
||||
from kivy.modules import Modules
|
||||
from kivy.event import EventDispatcher
|
||||
from kivy.properties import ListProperty, ObjectProperty, AliasProperty, \
|
||||
NumericProperty
|
||||
NumericProperty, OptionProperty, StringProperty
|
||||
|
||||
# late import
|
||||
VKeyboard = None
|
||||
|
@ -331,13 +332,32 @@ class WindowBase(EventDispatcher):
|
|||
degrees.
|
||||
'''
|
||||
|
||||
def _set_system_size(self, size):
|
||||
self._size = size
|
||||
|
||||
def _get_system_size(self):
|
||||
return self._size
|
||||
|
||||
system_size = AliasProperty(_get_system_size, None, bind=('_size', ))
|
||||
system_size = AliasProperty(_get_system_size, _set_system_size, bind=('_size', ))
|
||||
'''Real size of the window, without taking care of the rotation.
|
||||
'''
|
||||
|
||||
fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))
|
||||
'''If true, the window will be put in fullscreen mode, "auto". That's mean
|
||||
the screen size will not change, and use the current one to set the app
|
||||
fullscreen
|
||||
|
||||
.. versionadded:: 1.1.2
|
||||
'''
|
||||
|
||||
top = NumericProperty(None, allownone=True)
|
||||
left = NumericProperty(None, allownone=True)
|
||||
position = OptionProperty('auto', options=['auto', 'custom'])
|
||||
render_context = ObjectProperty(None)
|
||||
canvas = ObjectProperty(None)
|
||||
title = StringProperty('Kivy')
|
||||
|
||||
|
||||
def __new__(cls, **kwargs):
|
||||
if cls.__instance is None:
|
||||
cls.__instance = EventDispatcher.__new__(cls)
|
||||
|
@ -346,12 +366,12 @@ class WindowBase(EventDispatcher):
|
|||
def __init__(self, **kwargs):
|
||||
|
||||
kwargs.setdefault('force', False)
|
||||
kwargs.setdefault('config', None)
|
||||
|
||||
# don't init window 2 times,
|
||||
# except if force is specified
|
||||
if self.__initialized and not kwargs.get('force'):
|
||||
if WindowBase.__instance is not None and not kwargs.get('force'):
|
||||
return
|
||||
self.initialized = False
|
||||
|
||||
# event subsystem
|
||||
self.register_event_type('on_draw')
|
||||
|
@ -371,7 +391,41 @@ class WindowBase(EventDispatcher):
|
|||
self.register_event_type('on_key_up')
|
||||
self.register_event_type('on_dropfile')
|
||||
|
||||
super(WindowBase, self).__init__()
|
||||
# create a trigger for update/create the window when one of window
|
||||
# property changes
|
||||
self.trigger_create_window = Clock.create_trigger(self.create_window, -1)
|
||||
|
||||
# set the default window parameter according to the configuration
|
||||
if 'fullscreen' not in kwargs:
|
||||
fullscreen = Config.get('graphics', 'fullscreen')
|
||||
if fullscreen not in ('auto', 'fake'):
|
||||
fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')
|
||||
kwargs['fullscreen'] = fullscreen
|
||||
if 'width' not in kwargs:
|
||||
kwargs['width'] = Config.getint('graphics', 'width')
|
||||
if 'height' not in kwargs:
|
||||
kwargs['height'] = Config.getint('graphics', 'height')
|
||||
if 'rotation' not in kwargs:
|
||||
kwargs['rotation'] = Config.getint('graphics', 'rotation')
|
||||
if 'position' not in kwargs:
|
||||
kwargs['position'] = Config.get('graphics', 'position', 'auto')
|
||||
if 'top' in kwargs:
|
||||
kwargs['position'] = 'custom'
|
||||
kwargs['top'] = kwargs['top']
|
||||
else:
|
||||
kwargs['top'] = Config.getint('graphics', 'top')
|
||||
if 'left' in kwargs:
|
||||
kwargs['position'] = 'custom'
|
||||
kwargs['left'] = kwargs['left']
|
||||
else:
|
||||
kwargs['left'] = Config.getint('graphics', 'left')
|
||||
kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))
|
||||
|
||||
super(WindowBase, self).__init__(**kwargs)
|
||||
|
||||
# bind all the properties that need to recreate the window
|
||||
for prop in ('fullscreen', 'position', 'top', 'left', '_size', 'system_size'):
|
||||
self.bind(**{prop: self.trigger_create_window})
|
||||
|
||||
# init privates
|
||||
self._system_keyboard = Keyboard(window=self)
|
||||
|
@ -381,55 +435,10 @@ class WindowBase(EventDispatcher):
|
|||
self.children = []
|
||||
self.parent = self
|
||||
|
||||
# add view
|
||||
if 'view' in kwargs:
|
||||
self.add_widget(kwargs.get('view'))
|
||||
|
||||
# get window params, user options before config option
|
||||
params = {}
|
||||
|
||||
if 'fullscreen' in kwargs:
|
||||
params['fullscreen'] = kwargs.get('fullscreen')
|
||||
else:
|
||||
params['fullscreen'] = Config.get('graphics', 'fullscreen')
|
||||
if params['fullscreen'] not in ('auto', 'fake'):
|
||||
params['fullscreen'] = params['fullscreen'].lower() in \
|
||||
('true', '1', 'yes', 'yup')
|
||||
|
||||
if 'width' in kwargs:
|
||||
params['width'] = kwargs.get('width')
|
||||
else:
|
||||
params['width'] = Config.getint('graphics', 'width')
|
||||
|
||||
if 'height' in kwargs:
|
||||
params['height'] = kwargs.get('height')
|
||||
else:
|
||||
params['height'] = Config.getint('graphics', 'height')
|
||||
|
||||
if 'rotation' in kwargs:
|
||||
params['rotation'] = kwargs.get('rotation')
|
||||
else:
|
||||
params['rotation'] = Config.getint('graphics', 'rotation')
|
||||
|
||||
params['position'] = Config.get(
|
||||
'graphics', 'position', 'auto')
|
||||
if 'top' in kwargs:
|
||||
params['position'] = 'custom'
|
||||
params['top'] = kwargs.get('top')
|
||||
else:
|
||||
params['top'] = Config.getint('graphics', 'top')
|
||||
|
||||
if 'left' in kwargs:
|
||||
params['position'] = 'custom'
|
||||
params['left'] = kwargs.get('left')
|
||||
else:
|
||||
params['left'] = Config.getint('graphics', 'left')
|
||||
|
||||
# before creating the window
|
||||
__import__('kivy.core.gl')
|
||||
|
||||
# configure the window
|
||||
self.params = params
|
||||
self.create_window()
|
||||
|
||||
# attach modules + listener event
|
||||
|
@ -441,7 +450,7 @@ class WindowBase(EventDispatcher):
|
|||
self.configure_keyboards()
|
||||
|
||||
# mark as initialized
|
||||
self.__initialized = True
|
||||
self.initialized = True
|
||||
|
||||
def toggle_fullscreen(self):
|
||||
'''Toggle fullscreen on window'''
|
||||
|
@ -451,7 +460,7 @@ class WindowBase(EventDispatcher):
|
|||
'''Close the window'''
|
||||
pass
|
||||
|
||||
def create_window(self):
|
||||
def create_window(self, *largs):
|
||||
'''Will create the main window and configure it.
|
||||
|
||||
.. warning::
|
||||
|
@ -469,14 +478,32 @@ class WindowBase(EventDispatcher):
|
|||
Again, don't use this method unless you know exactly what you are
|
||||
doing !
|
||||
'''
|
||||
from kivy.core.gl import init_gl
|
||||
init_gl()
|
||||
# just to be sure, if the trigger is set, and if this method is manually
|
||||
# called, unset the trigger
|
||||
Clock.unschedule(self.create_window)
|
||||
|
||||
# create the render context and canvas
|
||||
from kivy.graphics import RenderContext, Canvas
|
||||
self.render_context = RenderContext()
|
||||
self.canvas = Canvas()
|
||||
self.render_context.add(self.canvas)
|
||||
print 'create window !!'
|
||||
if not self.initialized:
|
||||
from kivy.core.gl import init_gl
|
||||
init_gl()
|
||||
|
||||
# create the render context and canvas, only the first time.
|
||||
from kivy.graphics import RenderContext, Canvas
|
||||
self.render_context = RenderContext()
|
||||
self.canvas = Canvas()
|
||||
self.render_context.add(self.canvas)
|
||||
|
||||
else:
|
||||
# if we get initialized more than once, then reload opengl state
|
||||
# after the second time.
|
||||
from kivy.graphics.opengl_utils import gl_reload
|
||||
gl_reload()
|
||||
def ask_update(dt):
|
||||
self.canvas.ask_update()
|
||||
Clock.schedule_once(ask_update, 0)
|
||||
|
||||
# ensure the gl viewport is correct
|
||||
self.update_viewport()
|
||||
|
||||
def on_flip(self):
|
||||
'''Flip between buffers (event)'''
|
||||
|
@ -530,7 +557,7 @@ class WindowBase(EventDispatcher):
|
|||
|
||||
.. versionadded:: 1.0.5
|
||||
'''
|
||||
pass
|
||||
self.title = title
|
||||
|
||||
def set_icon(self, filename):
|
||||
'''Set the icon of the window
|
||||
|
|
|
@ -32,9 +32,12 @@ glReadPixels = GL_RGBA = GL_UNSIGNED_BYTE = None
|
|||
|
||||
class WindowPygame(WindowBase):
|
||||
|
||||
def create_window(self):
|
||||
params = self.params
|
||||
def create_window(self, *largs):
|
||||
# ensure the mouse is still not up after window creation, otherwise, we
|
||||
# have some weird bugs
|
||||
self.dispatch('on_mouse_up', 0, 0, 'all', [])
|
||||
|
||||
print 'window create'
|
||||
# force display to show (available only for fullscreen)
|
||||
displayidx = Config.getint('graphics', 'display')
|
||||
if not 'SDL_VIDEO_FULLSCREEN_HEAD' in environ and displayidx != -1:
|
||||
|
@ -47,11 +50,12 @@ class WindowPygame(WindowBase):
|
|||
# right now, activate resizable window only on linux.
|
||||
# on window / macosx, the opengl context is lost, and we need to
|
||||
# reconstruct everything. Check #168 for a state of the work.
|
||||
if platform() == 'linux':
|
||||
if platform() in ('linux', 'macosx', 'win'):
|
||||
self.flags |= pygame.RESIZABLE
|
||||
self.flags |= pygame.RESIZABLE
|
||||
|
||||
try:
|
||||
pygame.display.quit()
|
||||
pygame.display.init()
|
||||
except pygame.error, e:
|
||||
raise CoreCriticalException(e.message)
|
||||
|
@ -65,18 +69,17 @@ class WindowPygame(WindowBase):
|
|||
pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 16)
|
||||
pygame.display.gl_set_attribute(pygame.GL_STENCIL_SIZE, 1)
|
||||
pygame.display.gl_set_attribute(pygame.GL_ALPHA_SIZE, 8)
|
||||
pygame.display.set_caption('kivy')
|
||||
pygame.display.set_caption(self.title)
|
||||
|
||||
if params['position'] == 'auto':
|
||||
if self.position == 'auto':
|
||||
self._pos = None
|
||||
elif params['position'] == 'custom':
|
||||
self._pos = params['left'], params['top']
|
||||
elif self.position == 'custom':
|
||||
self._pos = self.left, self.top
|
||||
else:
|
||||
raise ValueError('position token in configuration accept only '
|
||||
'"auto" or "custom"')
|
||||
|
||||
self._fullscreenmode = params['fullscreen']
|
||||
if self._fullscreenmode == 'fake':
|
||||
if self.fullscreen == 'fake':
|
||||
Logger.debug('WinPygame: Set window to fake fullscreen mode')
|
||||
self.flags |= pygame.NOFRAME
|
||||
# if no position set, in fake mode, we always need to set the
|
||||
|
@ -85,7 +88,7 @@ class WindowPygame(WindowBase):
|
|||
self._pos = (0, 0)
|
||||
environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos
|
||||
|
||||
elif self._fullscreenmode:
|
||||
elif self.fullscreen is True:
|
||||
Logger.debug('WinPygame: Set window to fullscreen mode')
|
||||
self.flags |= pygame.FULLSCREEN
|
||||
|
||||
|
@ -111,10 +114,6 @@ class WindowPygame(WindowBase):
|
|||
except:
|
||||
Logger.exception('Window: cannot set icon')
|
||||
|
||||
# init ourself size + setmode
|
||||
# before calling on_resize
|
||||
self._size = params['width'], params['height']
|
||||
|
||||
# try to use mode with multisamples
|
||||
try:
|
||||
self._pygame_set_mode()
|
||||
|
@ -133,15 +132,16 @@ class WindowPygame(WindowBase):
|
|||
else:
|
||||
raise CoreCriticalException(e.message)
|
||||
|
||||
info = pygame.display.Info()
|
||||
self._size = (info.current_w, info.current_h)
|
||||
#self.dispatch('on_resize', *self._size)
|
||||
|
||||
super(WindowPygame, self).create_window()
|
||||
|
||||
# set mouse visibility
|
||||
pygame.mouse.set_visible(
|
||||
Config.getboolean('graphics', 'show_cursor'))
|
||||
|
||||
# set rotation
|
||||
self.rotation = params['rotation']
|
||||
|
||||
# if we are on android platform, automaticly create hooks
|
||||
if android:
|
||||
from kivy.support import install_android
|
||||
|
@ -151,8 +151,9 @@ class WindowPygame(WindowBase):
|
|||
pygame.display.quit()
|
||||
self.dispatch('on_close')
|
||||
|
||||
def set_title(self, title):
|
||||
pygame.display.set_caption(title)
|
||||
def on_title(self, instance, value):
|
||||
if self.initialized:
|
||||
pygame.display.set_caption(self.title)
|
||||
|
||||
def set_icon(self, filename):
|
||||
try:
|
||||
|
@ -220,6 +221,9 @@ class WindowPygame(WindowBase):
|
|||
if event.buttons == (0, 0, 0):
|
||||
continue
|
||||
x, y = event.pos
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
self._mouse_meta = self.modifiers
|
||||
self.dispatch('on_mouse_move', x, y, self.modifiers)
|
||||
|
||||
# mouse action
|
||||
|
@ -239,6 +243,11 @@ class WindowPygame(WindowBase):
|
|||
eventname = 'on_mouse_down'
|
||||
if event.type == pygame.MOUSEBUTTONUP:
|
||||
eventname = 'on_mouse_up'
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
self._mouse_meta = self.modifiers
|
||||
self._mouse_btn = btn
|
||||
self._mouse_down = eventname == 'on_mouse_down'
|
||||
self.dispatch(eventname, x, y, btn, self.modifiers)
|
||||
|
||||
# keyboard action
|
||||
|
@ -261,11 +270,7 @@ class WindowPygame(WindowBase):
|
|||
|
||||
# video resize
|
||||
elif event.type == pygame.VIDEORESIZE:
|
||||
self._size = event.size
|
||||
# don't use trigger here, we want to delay the resize event
|
||||
cb = self._do_resize
|
||||
Clock.unschedule(cb)
|
||||
Clock.schedule_once(cb, .1)
|
||||
self.system_size = event.size
|
||||
|
||||
elif event.type == pygame.VIDEOEXPOSE:
|
||||
self.canvas.ask_update()
|
||||
|
@ -285,16 +290,7 @@ class WindowPygame(WindowBase):
|
|||
Logger.debug('WinPygame: Unhandled event %s' % str(event))
|
||||
'''
|
||||
|
||||
def _do_resize(self, dt):
|
||||
Logger.debug('Window: Resize window to %s' % str(self._size))
|
||||
self._pygame_set_mode(self._size)
|
||||
self.dispatch('on_resize', *self._size)
|
||||
|
||||
def mainloop(self):
|
||||
# don't known why, but pygame required a resize event
|
||||
# for opengl, before mainloop... window reinit ?
|
||||
self.dispatch('on_resize', *self.size)
|
||||
|
||||
while not EventLoop.quit and EventLoop.status == 'started':
|
||||
try:
|
||||
self._mainloop()
|
||||
|
@ -312,22 +308,15 @@ class WindowPygame(WindowBase):
|
|||
# force deletion of window
|
||||
pygame.display.quit()
|
||||
|
||||
def _set_size(self, size):
|
||||
if super(WindowPygame, self)._set_size(size):
|
||||
self._pygame_set_mode()
|
||||
return True
|
||||
size = property(WindowBase._get_size, _set_size)
|
||||
|
||||
#
|
||||
# Pygame wrapper
|
||||
#
|
||||
def _pygame_set_mode(self, size=None):
|
||||
print '>>> pygame set mode', self._size, self.fullscreen, self.flags
|
||||
if size is None:
|
||||
size = self.size
|
||||
if self._fullscreenmode == 'auto':
|
||||
if self.fullscreen == 'auto':
|
||||
pygame.display.set_mode((0, 0), self.flags)
|
||||
info = pygame.display.Info()
|
||||
self._size = (info.current_w, info.current_h)
|
||||
else:
|
||||
pygame.display.set_mode(size, self.flags)
|
||||
|
||||
|
|
|
@ -181,6 +181,12 @@ class MouseMotionEventProvider(MotionEventProvider):
|
|||
return True
|
||||
|
||||
def on_mouse_release(self, win, x, y, button, modifiers):
|
||||
# special case, if button is all, then remove all the current mouses.
|
||||
if button == 'all':
|
||||
for cur in self.touches.values()[:]:
|
||||
self.remove_touch(cur)
|
||||
self.current_drag = None
|
||||
|
||||
width, height = EventLoop.window.system_size
|
||||
rx = x / float(width)
|
||||
ry = 1. - y / float(height)
|
||||
|
|
Loading…
Reference in New Issue