summaryrefslogtreecommitdiffstats
path: root/extra/arandr/arandr-0.1.3/screenlayout/widget.py
diff options
context:
space:
mode:
Diffstat (limited to 'extra/arandr/arandr-0.1.3/screenlayout/widget.py')
-rw-r--r--extra/arandr/arandr-0.1.3/screenlayout/widget.py406
1 files changed, 0 insertions, 406 deletions
diff --git a/extra/arandr/arandr-0.1.3/screenlayout/widget.py b/extra/arandr/arandr-0.1.3/screenlayout/widget.py
deleted file mode 100644
index 391d33779..000000000
--- a/extra/arandr/arandr-0.1.3/screenlayout/widget.py
+++ /dev/null
@@ -1,406 +0,0 @@
-from __future__ import division
-import os
-import stat
-import pango
-import pangocairo
-import gobject, gtk
-from .auxiliary import Position, Size, NORMAL, ROTATIONS, InadequateConfiguration
-from .xrandr import XRandR
-from .snap import Snap
-
-import gettext
-gettext.install('arandr')
-
-class ARandRWidget(gtk.DrawingArea):
- __gsignals__ = {
- 'expose-event':'override', # FIXME: still needed?
- 'changed':(gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
- }
-
- def __init__(self, factor=8, display=None, force_version=False):
- super(ARandRWidget, self).__init__()
-
- self._factor = factor
-
- self.set_size_request(1024//self.factor, 1024//self.factor) # best guess for now
-
- self.connect('button-press-event', self.click)
- self.set_events(gtk.gdk.BUTTON_PRESS_MASK)
-
- self.setup_draganddrop()
-
- self._xrandr = XRandR(display=display, force_version=force_version)
-
- #################### widget features ####################
-
- def _set_factor(self, f):
- self._factor = f
- self._update_size_request()
- self._force_repaint()
-
- factor = property(lambda self: self._factor, _set_factor)
-
- def abort_if_unsafe(self):
- if not len([x for x in self._xrandr.configuration.outputs.values() if x.active]):
- d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, _("Your configuration does not include an active monitor. Do you want to apply the configuration?"))
- result = d.run()
- d.destroy()
- if result == gtk.RESPONSE_YES:
- return False
- else:
- return True
- return False
-
- def error_message(self, message):
- d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, message)
- d.run()
- d.destroy()
-
- def _update_size_request(self):
- max_gapless = sum(max(o.size) if o.active else 0 for o in self._xrandr.configuration.outputs.values()) # this ignores that some outputs might not support rotation, but will always err at the side of caution.
- # have some buffer
- usable_size = int(max_gapless * 1.1)
- # don't request too large a window, but make sure very possible compination fits
- xdim = min(self._xrandr.state.virtual.max[0], usable_size)
- ydim = min(self._xrandr.state.virtual.max[1], usable_size)
- self.set_size_request(xdim//self.factor, ydim//self.factor)
-
- #################### loading ####################
-
- def load_from_file(self, file):
- data = open(file).read()
- template = self._xrandr.load_from_string(data)
- self._xrandr_was_reloaded()
- return template
-
- def load_from_x(self):
- self._xrandr.load_from_x()
- self._xrandr_was_reloaded()
- return self._xrandr.DEFAULTTEMPLATE
-
- def _xrandr_was_reloaded(self):
- self.sequence = sorted(self._xrandr.outputs)
- self._lastclick = (-1,-1)
-
- self._update_size_request()
- if self.window:
- self._force_repaint()
- self.emit('changed')
-
- def save_to_x(self):
- self._xrandr.save_to_x()
- self.load_from_x()
-
- def save_to_file(self, file, template=None, additional=None):
- data = self._xrandr.save_to_shellscript_string(template, additional)
- open(file, 'w').write(data)
- os.chmod(file, stat.S_IRWXU)
- self.load_from_file(file)
-
- #################### doing changes ####################
-
- def _set_something(self, which, on, data):
- old = getattr(self._xrandr.configuration.outputs[on], which)
- setattr(self._xrandr.configuration.outputs[on], which, data)
- try:
- self._xrandr.check_configuration()
- except InadequateConfiguration:
- setattr(self._xrandr.configuration.outputs[on], which, old)
- raise
-
- self._force_repaint()
- self.emit('changed')
-
- def set_position(self, on, pos):
- self._set_something('position', on, pos)
- def set_rotation(self, on, rot):
- self._set_something('rotation', on, rot)
- def set_resolution(self, on, res):
- self._set_something('mode', on, res)
-
- def set_active(self, on, active):
- v = self._xrandr.state.virtual
- o = self._xrandr.configuration.outputs[on]
-
- if not active and o.active:
- o.active = False
- # don't delete: allow user to re-enable without state being lost
- if active and not o.active:
- if hasattr(o, 'position'):
- o.active = True # nothing can go wrong, position already set
- else:
- pos = Position((0,0))
- for m in self._xrandr.state.outputs[on].modes:
- # determine first possible mode
- if m[0]<=v.max[0] and m[1]<=v.max[1]:
- mode = m
- break
- else:
- raise InadequateConfiguration("Smallest mode too large for virtual.")
-
- o.active = True
- o.position = pos
- o.mode = mode
- o.rotation = NORMAL
-
- self._force_repaint()
- self.emit('changed')
-
- #################### painting ####################
-
- def do_expose_event(self, event):
- cr = pangocairo.CairoContext(self.window.cairo_create())
- cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
- cr.clip()
-
- # clear
- cr.set_source_rgb(0,0,0)
- cr.rectangle(0,0,*self.window.get_size())
- cr.fill()
- cr.save()
-
- cr.scale(1/self.factor, 1/self.factor)
- cr.set_line_width(self.factor*1.5)
-
- self._draw(self._xrandr, cr)
-
- def _draw(self, xrandr, cr):
- cfg = xrandr.configuration
- state = xrandr.state
-
- cr.set_source_rgb(0.25,0.25,0.25)
- cr.rectangle(0,0,*state.virtual.max)
- cr.fill()
-
- cr.set_source_rgb(0.5,0.5,0.5)
- cr.rectangle(0,0,*cfg.virtual)
- cr.fill()
-
- for on in self.sequence:
- o = cfg.outputs[on]
- if not o.active: continue
-
- rect = (o.tentative_position if hasattr(o, 'tentative_position') else o.position) + o.size
- center = rect[0]+rect[2]/2, rect[1]+rect[3]/2
-
- # paint rectangle
- cr.set_source_rgba(1,1,1,0.7)
- cr.rectangle(*rect)
- cr.fill()
- cr.set_source_rgb(0,0,0)
- cr.rectangle(*rect)
- cr.stroke()
-
- # set up for text
- cr.save()
- textwidth = rect[3 if o.rotation.is_odd else 2]
- widthperchar = textwidth/len(on)
- textheight = int(widthperchar * 0.8) # i think this looks nice and won't overflow even for wide fonts
-
- newdescr = pango.FontDescription("sans")
- newdescr.set_size(textheight * pango.SCALE)
-
- # create text
- layout = cr.create_layout()
- layout.set_font_description(newdescr)
- layout.set_text(on)
-
- # position text
- layoutsize = layout.get_pixel_size()
- layoutoffset = -layoutsize[0]/2, -layoutsize[1]/2
- cr.move_to(*center)
- cr.rotate(o.rotation.angle)
- cr.rel_move_to(*layoutoffset)
-
- # pain text
- cr.show_layout(layout)
- cr.restore()
-
- def _force_repaint(self):
- # using self.allocation as rect is offset by the menu bar.
- self.window.invalidate_rect(gtk.gdk.Rectangle(0,0,self._xrandr.state.virtual.max[0]//self.factor,self._xrandr.state.virtual.max[1]//self.factor), False)
- # this has the side effect of not painting out of the available region on drag and drop
-
- #################### click handling ####################
-
- def click(self, widget, event):
- undermouse = self._get_point_outputs(event.x, event.y)
- if event.button == 1 and undermouse:
- which = self._get_point_active_output(event.x, event.y)
- if self._lastclick == (event.x, event.y): # this was the second click to that stack
- # push the highest of the undermouse windows below the lowest
- newpos = min(self.sequence.index(a) for a in undermouse)
- self.sequence.remove(which)
- self.sequence.insert(newpos,which)
- # sequence changed
- which = self._get_point_active_output(event.x, event.y)
- # pull the clicked window to the absolute top
- self.sequence.remove(which)
- self.sequence.append(which)
-
- self._lastclick = (event.x, event.y)
- self._force_repaint()
- if event.button == 3:
- if undermouse:
- target = [a for a in self.sequence if a in undermouse][-1]
- m = self._contextmenu(target)
- m.popup(None, None, None, event.button, event.time)
- else:
- m = self.contextmenu()
- m.popup(None, None, None, event.button, event.time)
-
- self._lastclick = (event.x, event.y) # deposit for drag and drop until better way found to determine exact starting coordinates
-
- def _get_point_outputs(self, x, y):
- x,y = x*self.factor, y*self.factor
- outputs = set()
- for on,o in self._xrandr.configuration.outputs.items():
- if not o.active: continue
- if o.position[0]-self.factor <= x <= o.position[0]+o.size[0]+self.factor and o.position[1]-self.factor <= y <= o.position[1]+o.size[1]+self.factor:
- outputs.add(on)
- return outputs
-
- def _get_point_active_output(self, x, y):
- undermouse = self._get_point_outputs(x, y)
- if not undermouse: raise IndexError("No output here.")
- active = [a for a in self.sequence if a in undermouse][-1]
- return active
-
- #################### context menu ####################
-
- def contextmenu(self):
- m = gtk.Menu()
- for on in self._xrandr.outputs:
- i = gtk.MenuItem(on)
- i.props.submenu = self._contextmenu(on)
- m.add(i)
- m.show_all()
- return m
-
- def _contextmenu(self, on):
- m = gtk.Menu()
- oc = self._xrandr.configuration.outputs[on]
- os = self._xrandr.state.outputs[on]
-
- enabled = gtk.CheckMenuItem(_("Active"))
- enabled.props.active = oc.active
- if not oc.active and not os.connected:
- enabled.props.sensitive = False
- enabled.connect('activate', lambda menuitem: self.set_active(on, menuitem.props.active))
-
- m.add(enabled)
-
- if oc.active:
- res_m = gtk.Menu()
- for r in os.modes:
- i = gtk.CheckMenuItem("%sx%s"%r)
- i.props.draw_as_radio = True
- i.props.active = (oc.mode == r)
- def _res_set(menuitem, on, r):
- try:
- self.set_resolution(on, r)
- except InadequateConfiguration, e:
- self.error_message(_("Setting this resolution is not possible here: %s")%e.message)
- i.connect('activate', _res_set, on, r)
- res_m.add(i)
-
- or_m = gtk.Menu()
- for r in ROTATIONS:
- i = gtk.CheckMenuItem("%s"%r)
- i.props.draw_as_radio = True
- i.props.active = (oc.rotation == r)
- def _rot_set(menuitem, on, r):
- try:
- self.set_rotation(on, r)
- except InadequateConfiguration, e:
- self.error_message(_("This orientation is not possible here: %s")%e.message)
- i.connect('activate', _rot_set, on, r)
- if r not in os.rotations:
- i.props.sensitive = False
- or_m.add(i)
-
- res_i = gtk.MenuItem(_("Resolution"))
- res_i.props.submenu = res_m
- or_i = gtk.MenuItem(_("Orientation"))
- or_i.props.submenu = or_m
-
- m.add(res_i)
- m.add(or_i)
-
- m.show_all()
- return m
-
- #################### drag&drop ####################
-
- def setup_draganddrop(self):
- self.drag_source_set(gtk.gdk.BUTTON1_MASK, [('screenlayout-output', gtk.TARGET_SAME_WIDGET, 0)], 0)
- self.drag_dest_set(0, [('screenlayout-output', gtk.TARGET_SAME_WIDGET, 0)], 0)
- #self.drag_source_set(gtk.gdk.BUTTON1_MASK, [], 0)
- #self.drag_dest_set(0, [], 0)
-
- self._draggingfrom = None
- self._draggingoutput = None
- self.connect('drag-begin', self._dragbegin_cb)
- self.connect('drag-motion', self._dragmotion_cb)
- self.connect('drag-drop', self._dragdrop_cb)
- self.connect('drag-end', self._dragend_cb)
-
- self._lastclick = (0,0)
-
- def _dragbegin_cb(self, widget, context):
- try:
- output = self._get_point_active_output(*self._lastclick)
- except IndexError:
- # FIXME: abort?
- context.set_icon_stock(gtk.STOCK_CANCEL, 10,10)
- return None
-
- self._draggingoutput = output
- self._draggingfrom = self._lastclick
- context.set_icon_stock(gtk.STOCK_FULLSCREEN, 10,10)
-
- self._draggingsnap = Snap(
- self._xrandr.configuration.outputs[self._draggingoutput].size,
- self.factor*5,
- [(Position((0,0)),self._xrandr.state.virtual.max)]+[
- (v.position, v.size) for (k,v) in self._xrandr.configuration.outputs.items() if k!=self._draggingoutput and v.active
- ]
- )
-
- def _dragmotion_cb(self, widget, context, x, y, time):
- if not 'screenlayout-output' in context.targets: # from outside
- return False
- if not self._draggingoutput: # from void; should be already aborted
- return False
-
- context.drag_status(gtk.gdk.ACTION_MOVE, time)
-
- rel = x-self._draggingfrom[0], y-self._draggingfrom[1]
-
- oldpos = self._xrandr.configuration.outputs[self._draggingoutput].position
- newpos = Position((oldpos[0]+self.factor*rel[0], oldpos[1]+self.factor*rel[1]))
- self._xrandr.configuration.outputs[self._draggingoutput].tentative_position = self._draggingsnap.suggest(newpos)
- self._force_repaint()
-
- return True
-
- def _dragdrop_cb(self, widget, context, x, y, time):
- if not self._draggingoutput:
- return
-
- try:
- self.set_position(self._draggingoutput, self._xrandr.configuration.outputs[self._draggingoutput].tentative_position)
- except InadequateConfiguration:
- context.finish(False, False, time)
- #raise # snapping back to the original position should be enought feedback
-
- context.finish(True, False, time)
-
- def _dragend_cb(self, widget, context):
- try:
- del self._xrandr.configuration.outputs[self._draggingoutput].tentative_position
- except KeyError:
- pass # already reloaded
- self._draggingoutput = None
- self._draggingfrom = None
- self._force_repaint()