diff --git a/discover_overlay/draggable_window.py b/discover_overlay/draggable_window.py index e277dcc..3432594 100644 --- a/discover_overlay/draggable_window.py +++ b/discover_overlay/draggable_window.py @@ -6,7 +6,7 @@ import logging class DraggableWindow(Gtk.Window): - def __init__(self, x=0, y=0, w=300, h=300, message="Message"): + def __init__(self, x=0, y=0, w=300, h=300, message="Message",settings=None): Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP) if w < 100: w = 100 @@ -16,6 +16,7 @@ class DraggableWindow(Gtk.Window): self.y = y self.w = w self.h = h + self.settings=settings self.message = message self.set_size_request(50, 50) @@ -127,3 +128,8 @@ class DraggableWindow(Gtk.Window): context.rectangle(0, sh - 32, sw, 32) context.fill() + + def get_coords(self): + (x, y) = self.placement_window.get_position() + (w, h) = self.placement_window.get_size() + return (x,y,w,h) diff --git a/discover_overlay/draggable_window_wayland.py b/discover_overlay/draggable_window_wayland.py new file mode 100644 index 0000000..328b360 --- /dev/null +++ b/discover_overlay/draggable_window_wayland.py @@ -0,0 +1,137 @@ +import gi +gi.require_version("Gtk", "3.0") +import cairo +from gi.repository import Gtk, Gdk, GtkLayerShell +import logging + + +class DraggableWindowWayland(Gtk.Window): + def __init__(self, x=0, y=0, w=300, h=300, message="Message", settings=None): + Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL) + if w < 100: + w = 100 + if h < 100: + h = 100 + self.x = x + self.y = y + self.w = w + self.h = h + self.settings=settings + self.message = message + self.set_size_request(50, 50) + + self.connect('draw', self.draw) + self.connect('motion-notify-event', self.drag) + self.connect('button-press-event', self.button_press) + self.connect('button-release-event', self.button_release) + + self.set_app_paintable(True) + self.monitor = 0 + + self.drag_type = None + self.drag_x = 0 + self.drag_y = 0 + GtkLayerShell.init_for_window(self) + GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP) + GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True) + GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.RIGHT, True) + GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.BOTTOM, True) + GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True) + + self.show_all() + #self.force_location() + + def force_location(self): + (sx, sy)= self.get_size() + if self.x < 0: + self.x=0 + if self.y < 0: + self.y=0 + if self.x + self.w > sx: + self.x = sx - self.w + if self.y + self.h > sy: + self.y = sy - self.h + self.queue_draw() + + def drag(self, w, event): + if event.state & Gdk.ModifierType.BUTTON1_MASK: + if self.drag_type == 1: + # Center is move + self.x += event.x - self.drag_x + self.y += event.y - self.drag_y + self.drag_x = event.x + self.drag_y = event.y + + self.force_location() + elif self.drag_type == 2: + # Right edge + self.w += event.x - self.drag_x + self.drag_x = event.x + self.force_location() + elif self.drag_type == 3: + # Bottom edge + self.h += event.y - self.drag_y + self.drag_y = event.y + self.force_location() + else: + # Bottom Right + self.w += event.x - self.drag_x + self.h += event.y - self.drag_y + self.drag_x = event.x + self.drag_y = event.y + self.force_location() + + def button_press(self, w, event): + px = event.x - self.x + py = event.y - self.y + + if not self.drag_type: + self.drag_type = 1 + # Where in the window did we press? + if px < 20 and py<20: + self.settings.change_placement(None) + if py > self.h - 32: + self.drag_type += 2 + if px > self.w - 32: + self.drag_type += 1 + self.drag_x = event.x + self.drag_y = event.y + + def button_release(self, w, event): + self.drag_type = None + + def draw(self, widget, context): + context.translate(self.x, self.y) + context.save() + context.rectangle(0,0,self.w,self.h) + context.clip() + + context.set_source_rgba(1.0, 1.0, 0.0, 0.7) + # Don't layer drawing over each other, always replace + context.set_operator(cairo.OPERATOR_SOURCE) + context.paint() + # Get size of window + + # Draw text + context.set_source_rgba(0.0, 0.0, 0.0, 1.0) + xb, yb, w, h, dx, dy = context.text_extents(self.message) + context.move_to(self.w / 2 - w / 2, self.h / 2 - h / 2) + context.show_text(self.message) + + # Draw resizing edges + context.set_source_rgba(0.0, 0.0, 1.0, 0.5) + context.rectangle(self.w - 32, 0, 32, self.h) + context.fill() + + context.rectangle(0, self.h - 32, self.w, 32) + context.fill() + + # Draw Done! + context.set_source_rgba(0.0, 1.0, 0.0, 0.5) + context.rectangle(0, 0, 20,20) + context.fill() + context.restore() + + + def get_coords(self): + return (self.x,self.y,self.w,self.h) \ No newline at end of file diff --git a/discover_overlay/overlay.py b/discover_overlay/overlay.py index 8d5d101..8c0e5ef 100644 --- a/discover_overlay/overlay.py +++ b/discover_overlay/overlay.py @@ -65,7 +65,7 @@ class OverlayWindow(Gtk.Window): GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True) def draw(self, widget, context): - pass + self.do_draw(context) def do_draw(self, context): pass @@ -98,38 +98,47 @@ class OverlayWindow(Gtk.Window): self.get_window().shape_combine_region(None, 0, 0) def force_location(self): - self.set_decorated(False) - self.set_keep_above(True) - display = Gdk.Display.get_default() - if "get_monitor" in dir(display): - monitor = display.get_monitor(self.monitor) - geometry = monitor.get_geometry() - scale_factor = monitor.get_scale_factor() - if not self.floating: - w = scale_factor * geometry.width - h = scale_factor * geometry.height - x = geometry.x - y = geometry.y - self.resize(w, h) - self.move(x, y) + if not self.is_wayland: + self.set_decorated(False) + self.set_keep_above(True) + display = Gdk.Display.get_default() + if "get_monitor" in dir(display): + monitor = display.get_monitor(self.monitor) + geometry = monitor.get_geometry() + scale_factor = monitor.get_scale_factor() + if not self.floating: + w = scale_factor * geometry.width + h = scale_factor * geometry.height + x = geometry.x + y = geometry.y + self.resize(w, h) + self.move(x, y) + else: + self.move(self.x, self.y) + self.resize(self.w, self.h) else: - self.move(self.x, self.y) - self.resize(self.w, self.h) - else: - if not self.floating: - screen = display.get_default_screen() - w = screen.width() - h = screen.height() - x = 0 - y = 0 - else: - self.move(self.x, self.y) - self.resize(self.w, self.h) + if not self.floating: + screen = display.get_default_screen() + w = screen.width() + h = screen.height() + x = 0 + y = 0 + else: + self.move(self.x, self.y) + self.resize(self.w, self.h) + if not self.floating: + (w,h) = self.get_size() + self.w = w + self.h = h self.redraw() def redraw(self): gdkwin = self.get_window() + if not self.floating: + (w,h) = self.get_size() + self.w = w + self.h = h if gdkwin: if not self.compositing or self.force_xshape: diff --git a/discover_overlay/text_overlay.py b/discover_overlay/text_overlay.py index 37460a1..5555f46 100644 --- a/discover_overlay/text_overlay.py +++ b/discover_overlay/text_overlay.py @@ -118,14 +118,30 @@ class TextOverlayWindow(OverlayWindow): self.attachment[id] = pix self.redraw() + def draw(self, widget, ctx): + self.do_draw(ctx) + def do_draw(self, context): self.context = context context.set_antialias(cairo.ANTIALIAS_GOOD) (w, h) = self.get_size() - # Make background transparent context.set_source_rgba(0.0, 0.0, 0.0, 0.0) + context.set_operator(cairo.OPERATOR_SOURCE) context.paint() + context.save() + if self.is_wayland: + # Special case! + # The window is full-screen regardless of what the user has selected. Because Wayland + # We need to set a clip and a transform to imitate original behaviour + + w = self.w + h = self.h + context.translate(self.x, self.y) + context.rectangle(0,0,w,h) + context.clip() + + cy = h tnow = time.time() @@ -155,18 +171,19 @@ class TextOverlayWindow(OverlayWindow): if cy <= 0: # We've done enough break + if self.is_wayland: + context.restore() def draw_attach(self, y, url): - (w, h) = self.get_size() if url in self.attachment and self.attachment[url]: pix = self.attachment[url] iw = pix.get_width() ih = pix.get_height() - iw = min(iw, w) - ih = min(ih, (h * .7)) + iw = min(iw, self.w) + ih = min(ih, (self.h * .7)) (ax, ay, aw, ah) = get_aspected_size(pix, iw, ih) self.col(self.bg_col) - self.context.rectangle(0, y - ah, w, ah) + self.context.rectangle(0, y - ah, self.w, ah) self.context.fill() self.context.set_operator(cairo.OPERATOR_OVER) @@ -176,13 +193,12 @@ class TextOverlayWindow(OverlayWindow): return y def draw_text(self, y, text): - (w, h) = self.get_size() layout = self.create_pango_layout(text) layout.set_markup(text, -1) attr = layout.get_attributes() - layout.set_width(Pango.SCALE * w) + layout.set_width(Pango.SCALE * self.w) layout.set_spacing(Pango.SCALE * 3) if(self.text_font): font = Pango.FontDescription( @@ -190,7 +206,7 @@ class TextOverlayWindow(OverlayWindow): layout.set_font_description(font) tw, th = layout.get_pixel_size() self.col(self.bg_col) - self.context.rectangle(0, y - th, w, th) + self.context.rectangle(0, y - th, self.w, th) self.context.fill() self.context.set_operator(cairo.OPERATOR_OVER) self.col(self.fg_col) diff --git a/discover_overlay/text_settings.py b/discover_overlay/text_settings.py index 6deee9e..43f7d59 100644 --- a/discover_overlay/text_settings.py +++ b/discover_overlay/text_settings.py @@ -3,6 +3,7 @@ gi.require_version("Gtk", "3.0") import json from configparser import ConfigParser from .draggable_window import DraggableWindow +from .draggable_window_wayland import DraggableWindowWayland from .settings import SettingsWindow from gi.repository import Gtk, Gdk, Pango import logging @@ -189,10 +190,10 @@ class TextSettingsWindow(SettingsWindow): config.set("text", "monitor", self.monitor) config.set("text", "enabled", "%d" % (int(self.enabled))) config.set("text", "floating", "%s" % (int(self.floating))) - config.set("text", "floating_x", "%s" % (self.floating_x)) - config.set("text", "floating_y", "%s" % (self.floating_y)) - config.set("text", "floating_w", "%s" % (self.floating_w)) - config.set("text", "floating_h", "%s" % (self.floating_h)) + config.set("text", "floating_x", "%s" % (int(self.floating_x))) + config.set("text", "floating_y", "%s" % (int(self.floating_y))) + config.set("text", "floating_w", "%s" % (int(self.floating_w))) + config.set("text", "floating_h", "%s" % (int(self.floating_h))) config.set("text", "channel", self.channel) config.set("text", "guild", self.guild) config.set("text", "bg_col", json.dumps(self.bg_col)) @@ -394,22 +395,31 @@ class TextSettingsWindow(SettingsWindow): def change_placement(self, button): if self.placement_window: - (x, y) = self.placement_window.get_position() - (w, h) = self.placement_window.get_size() + (x,y,w,h) = self.placement_window.get_coords() self.floating_x = x self.floating_y = y self.floating_w = w self.floating_h = h self.overlay.set_floating(True, x, y, w, h) self.save_config() - button.set_label("Place Window") + if not self.overlay.is_wayland: + button.set_label("Place Window") self.placement_window.close() self.placement_window = None else: - self.placement_window = DraggableWindow( - x=self.floating_x, y=self.floating_y, w=self.floating_w, h=self.floating_h, message="Place & resize this window then press Save!") - button.set_label("Save this position") + if self.overlay.is_wayland: + self.placement_window = DraggableWindowWayland( + x=self.floating_x, y=self.floating_y, + w=self.floating_w, h=self.floating_h, + message="Place & resize this window then press Green!",settings=self) + else: + self.placement_window = DraggableWindow( + x=self.floating_x, y=self.floating_y, + w=self.floating_w, h=self.floating_h, + message="Place & resize this window then press Save!",settings=self) + if not self.overlay.is_wayland: + button.set_label("Save this position") def change_align_type_edge(self, button): if button.get_active(): diff --git a/discover_overlay/voice_overlay.py b/discover_overlay/voice_overlay.py index edb7b18..be2438d 100644 --- a/discover_overlay/voice_overlay.py +++ b/discover_overlay/voice_overlay.py @@ -144,12 +144,26 @@ class VoiceOverlayWindow(OverlayWindow): def do_draw(self, context): self.context = context context.set_antialias(cairo.ANTIALIAS_GOOD) - + # Get size of window + (w, h) = self.get_size() # Make background transparent self.set_wind_col() # Don't layer drawing over each other, always replace context.set_operator(cairo.OPERATOR_SOURCE) context.paint() + context.save() + if self.is_wayland: + # Special case! + # The window is full-screen regardless of what the user has selected. Because Wayland + # We need to set a clip and a transform to imitate original behaviour + + w = self.w + h = self.h + context.translate(self.x, self.y) + context.rectangle(0,0,w,h) + context.clip() + + context.set_operator(cairo.OPERATOR_OVER) if not self.connected: return @@ -183,8 +197,6 @@ class VoiceOverlayWindow(OverlayWindow): pass # Not in list self.users_to_draw.insert(0, self_user) - # Get size of window - (w, h) = self.get_size() # Calculate height needed to show overlay height = (len(self.users_to_draw) * self.avatar_size) + \ (len(self.users_to_draw) + 1) * self.icon_spacing @@ -203,6 +215,8 @@ class VoiceOverlayWindow(OverlayWindow): rh += self.avatar_size + self.icon_spacing # Don't hold a ref + if self.is_wayland: + context.restore() self.context = None def recv_avatar(self, id, pix): @@ -226,7 +240,6 @@ class VoiceOverlayWindow(OverlayWindow): # Set the key with no value to avoid spamming requests self.avatars[user["id"]] = None - (w, h) = self.get_size() c = None mute = False deaf = False @@ -243,14 +256,14 @@ class VoiceOverlayWindow(OverlayWindow): if self.align_right: if not self.icon_only: self.draw_text( - context, user["friendlyname"], w - self.avatar_size - self.horz_edge_padding, y) + context, user["friendlyname"], self.w - self.avatar_size - self.horz_edge_padding, y) self.draw_avatar_pix( - context, pix, w - self.avatar_size - self.horz_edge_padding, y, c) + context, pix, self.w - self.avatar_size - self.horz_edge_padding, y, c) if deaf: - self.draw_deaf(context, w - self.avatar_size - + self.draw_deaf(context, self.w - self.avatar_size - self.horz_edge_padding, y) elif mute: - self.draw_mute(context, w - self.avatar_size - + self.draw_mute(context, self.w - self.avatar_size - self.horz_edge_padding, y) else: if not self.icon_only: diff --git a/discover_overlay/voice_settings.py b/discover_overlay/voice_settings.py index aea4051..79130f7 100644 --- a/discover_overlay/voice_settings.py +++ b/discover_overlay/voice_settings.py @@ -3,6 +3,7 @@ gi.require_version("Gtk", "3.0") import json from configparser import ConfigParser from .draggable_window import DraggableWindow +from .draggable_window_wayland import DraggableWindowWayland from .settings import SettingsWindow from gi.repository import Gtk, Gdk, Pango import logging @@ -340,24 +341,30 @@ class VoiceSettingsWindow(SettingsWindow): def change_placement(self, button): if self.placement_window: - (x, y) = self.placement_window.get_position() - (w, h) = self.placement_window.get_size() + (x,y,w,h) = self.placement_window.get_coords() self.floating_x = x self.floating_y = y self.floating_w = w self.floating_h = h self.overlay.set_floating(True, x, y, w, h) self.save_config - button.set_label("Place Window") - + if not self.overlay.is_wayland: + button.set_label("Place Window") self.placement_window.close() self.placement_window = None else: - self.placement_window = DraggableWindow( - x=self.floating_x, y=self.floating_y, - w=self.floating_w, h=self.floating_h, - message="Place & resize this window then press Save!") - button.set_label("Save this position") + if self.overlay.is_wayland: + self.placement_window = DraggableWindowWayland( + x=self.floating_x, y=self.floating_y, + w=self.floating_w, h=self.floating_h, + message="Place & resize this window then press Green!",settings=self) + else: + self.placement_window = DraggableWindow( + x=self.floating_x, y=self.floating_y, + w=self.floating_w, h=self.floating_h, + message="Place & resize this window then press Save!",settings=self) + if not self.overlay.is_wayland: + button.set_label("Save this position") def change_align_type_edge(self, button): if button.get_active():