xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #539: tabbed-client.patch

File tabbed-client.patch, 7.1 KB (added by Antoine Martin, 8 years ago)

stub for a tabbed client

  • xpra/client/gtk2/tabbed_client.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2014 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import gobject
     7import gtk
     8from gtk import gdk
     9
     10from xpra.client.gtk2.gtk2_window_base import GTK2_WINDOW_EVENT_MASK
     11from xpra.client.gtk2.client import XpraClient as GTK2_XpraClient
     12from xpra.client.client_window_base import ClientWindowBase
     13
     14from xpra.log import Logger
     15log = Logger("gtk", "client")
     16
     17
     18class Tab(ClientWindowBase):
     19
     20    def __init__(self, client, group_leader, wid, *args):
     21        ClientWindowBase.__init__(self, client, group_leader, wid, *args)
     22        log.info("Tab.__init__%s", [client, group_leader, wid]+list(args))
     23        self.container = None
     24        self.client = None
     25        self._backing = None
     26
     27    def show(self):
     28        pass
     29
     30    def get_window(self):
     31        return self.container.window
     32
     33    def is_mapped(self):
     34        #always mapped, instantly!
     35        return True
     36    def is_realized(self):
     37        #always realized, instantly!
     38        return True
     39
     40    def new_backing(self, *size):
     41        #we should have one already!
     42        pass
     43
     44    def unmaximize(self):
     45        pass
     46
     47    def set_modal(self, modal):
     48        #not used
     49        pass
     50
     51    def set_icon_name(self, icon_name):
     52        #use this if we don't have a real icon
     53        pass
     54
     55    def set_title(self, title):
     56        #TODO: show title in tab button
     57        pass
     58
     59    def set_workspace(self):
     60        #does not make sense
     61        pass
     62
     63    def get_window_geometry(self):
     64        #TODO: get from container window
     65        return None
     66
     67    def apply_geometry_hints(self, hints):
     68        #not sure what to do with those!
     69        pass
     70
     71    def queue_draw(self, x, y, width, height):
     72        log.info("queue_draw%s", (x, y, width, height))
     73        self.container.queue_draw(x, y, width, height)
     74
     75    def set_fullscreen(self, fullscreen):
     76        #TODO: pass to container, and show just this tab fullscreen..
     77        pass
     78
     79
     80class TabContainerWindow(gtk.Window):
     81
     82    def __init__(self, client):
     83        self.client = client
     84        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
     85        self.set_app_paintable(True)
     86        self.add_events(GTK2_WINDOW_EVENT_MASK)
     87        # tell KDE/oxygen not to intercept clicks
     88        # see: https://bugs.kde.org/show_bug.cgi?id=274485
     89        self.set_data("_kde_no_window_grab", 1)
     90        self.set_default_size(640, 480)
     91        def tab_close(*args):
     92            self.client.quit(0)
     93        self.connect("delete_event", tab_close)
     94
     95        #the main context box:
     96        self.vbox = gtk.VBox()
     97        #simple tab button container (for now)
     98        self.hbox = gtk.HBox()
     99        self.label = gtk.Label("hello")
     100        self.hbox.add(self.label)
     101        self.vbox.pack_start(self.hbox, False, False, 0)
     102        self.alignment = gtk.Alignment(xalign=0.0, yalign=0.0, xscale=1.0, yscale=1.0)
     103        self.vbox.pack_start(self.alignment, True, True, 0)
     104        self.contents = gtk.EventBox()
     105        self.alignment.add(self.contents)
     106        #for now, let's use a shared backing:
     107        from xpra.client.gtk2.pixmap_backing import PixmapBacking
     108        self.backing = PixmapBacking(-1, 640, 480, False)
     109        self.backing.init(640, 480)
     110
     111        self.vbox.show_all()
     112        self.add(self.vbox)
     113
     114    def queue_draw(self, x, y, width, height):
     115        assert self.window
     116        self.window.invalidate_rect(gdk.Rectangle(x, y, width, height), False)
     117
     118    def do_expose_event(self, event):
     119        log.info("do_expose_event(%s) area=%s", event, event.area)
     120        if not (self.flags() & gtk.MAPPED) or self.backing is None:
     121            return
     122        self.hbox.do_expose_event(self, event)
     123        w,h = self.window.get_size()
     124        if w>=32768 or h>=32768:
     125            log.error("cannot paint on window which is too large: %sx%s !", w, h)
     126            return
     127        context = self.window.cairo_create()
     128        context.rectangle(event.area)
     129        context.clip()
     130        self.backing.cairo_draw(context)
     131
     132    def get_contents_geometry(self):
     133        #position of the window contents:
     134        ox, oy = self.window.get_origin()
     135        #position of the contents inside the window:
     136        x, y = self.contents.translate_coordinates(self, 0, 0)
     137        w, h = self.contents.window.get_size()
     138        #return self.window.get_geometry()[:4]
     139        return ox+x, oy+y, w, h
     140
     141
     142gobject.type_register(TabContainerWindow)
     143
     144
     145class XpraClient(GTK2_XpraClient):
     146
     147    def init(self, opts):
     148        GTK2_XpraClient.init(self, opts)
     149        self.ClientWindowClass = Tab
     150        log("init(..) ClientWindowClass=%s", self.ClientWindowClass)
     151        self.container = TabContainerWindow(self)
     152
     153    def run(self):
     154        self.container.show()
     155        GTK2_XpraClient.run(self)
     156
     157    def get_client_window_classes(self, metadata, override_redirect):
     158        if override_redirect:
     159            return GTK2_XpraClient.get_client_window_classes(self, metadata, override_redirect)
     160        return [Tab]
     161
     162    def make_new_window(self, *args):
     163        w = GTK2_XpraClient.make_new_window(self, *args)
     164        if w:
     165            w.container = self.container
     166            w._backing = self.container.backing
     167            self.send_map_event(w)
     168        log.info("make_new_window%s=%s", args, w)
     169        return w
     170
     171    def send_map_event(self, window):
     172        #get geometry from the container:
     173        wid = self._window_to_id[window]
     174        x, y, w, h = self.container.get_contents_geometry()
     175        log.info("sending map event: %s", (x, y, w, h))
     176        self.send("map-window", wid, x, y, w, h, {})
     177
     178    def client_type(self):
     179        return "Python/Gtk2-Tabbed"
     180
     181    def client_toolkit(self):
     182        return "gtk2"
     183
     184    def get_supported_window_layouts(self):
     185        return  {"default" : Tab}
     186
     187    def _process_raise_window(self, packet):
     188        #TODO: show the right tab!
     189        pass
     190
     191    def _process_pointer_grab(self, packet):
     192        #TODO: show the right tab then call GTK2 code
     193        pass
     194
     195    def _process_pointer_ungrab(self, packet):
     196        #TODO: show the right tab then call GTK2 code
     197        pass
     198
     199    def destroy_window(self, wid, window):
     200        #TODO: remove tab
     201        GTK2_XpraClient.destroy_window(self, wid, window)
     202
  • xpra/scripts/main.py

     
    976976
    977977    if check_toolkit("gtk.gdk", "xpra.client.gtk2"):
    978978        toolkits["gtk2"] = "xpra.client.gtk2.client"
     979        toolkits["tabbed"] = "xpra.client.gtk2.tabbed_client"
    979980    elif check_toolkit("gi", "xpra.client.gtk3"):
    980981        toolkits["gtk3"] = "xpra.client.gtk3.client"
    981982    if check_toolkit("PyQt4.QtCore", "PyQt4.QtGui", "xpra.client.qt4"):