Coder Social home page Coder Social logo

Support for multiple windows? about pywebview HOT 34 CLOSED

r0x0r avatar r0x0r commented on May 18, 2024
Support for multiple windows?

from pywebview.

Comments (34)

cuibonobo avatar cuibonobo commented on May 18, 2024 1

Ok, let me see if I'm thinking about this correctly: instead of webview.create_window() you would do something like mywindow = webview.create_window_multiple(), so now instead of, for example, webview.load_url() it would be something like mywindow.load_url()?

The problem is that in order for that to work, the BrowserView class shouldn't implement the singleton pattern. So instead of doing BrowserView.instance = self when we are initializing the BrowserView, we need to somehow keep track of the number of windows.

Maybe what can be done is instead of having instance as a class property, use a list called windows. That way BrowserView.__init__() can do something like this:

self.windows.append(self)

This way we wouldn't actually need to add a create_window_multiple function: calling create_window automatically appends a window to the list, and it return the browser object so it can be manipulated directly. If you don't want to work with objects, you can just call the module functions like normal. Following this plan, the module functions should access windows[0] instead of instance. For example:

def load_url(url):
    BrowserView.windows[0].load_url(url)

from pywebview.

cateee avatar cateee commented on May 18, 2024 1

Could not be done directly in javascript on the main window? That window could create and handle other windows. The only thing it cannot be done, it to destroy the main windows leaving the other windows open.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024 1

This is indeed a cool feature, pretty useful. I think @cuibonobo's idea is the best
way to implement the backend. Regarding the frontend, I have the same idea as
@cateee's, using HTML/JS. Thus we don't need to introduce any new API.

I have tried this in Cocoa and it works really smooth. Screenshot:

screen shot 2017-04-22 at 2 11 34 pm
Yes, that's seven Pywebview instances running in parallel!

It's pretty straight-forward, checkout the multiple-wins-cocoa branch of my fork
here. On other platforms, I guess the changes to the BrowserView class could
imitate this Cocoa implementation. Only the ways to capture the HTML/JS requests
would require reading API docs of the respective frameworks.

I don't know, can we have a try @r0x0r?

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024 1

Sounds reasonable. Let's start with your approach and see where it leads from there. One thing that needs to take into account the windowspec string of windows.open function. That way we can set up the properties of a new window from Javascript.

I have cloned your branch into https://github.com/r0x0r/pywebview/tree/multiple-windows-support. Please feel free to contribute pull requests to it.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024 1

The multi-window JS bridge fails on all the platforms. There maybe something wrong with the test.
I fixed debugging on Cocoa. The setting is global for all the opened windows. There is probably no need to make it specific to individual windows.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

This is a good suggestion. One way to do it would be to leave the current API unchanged and introduce an additonal method create_window_multiple (or something like that) that would return a BrowserView object.
This would require unifying the BrowserView objects across platforms and re-thinking a threading model. According to the current model, GUI is run in a main thread and backend logic in a separate daemon thread.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

Yeah, something like this would do a trick. The main obstacle is that GUI frameworks dictate that GUI must be run in a primary thread. So changing a thread model and spawning multiple windows with create_window_multiple in separate threads would not work, unless multiprocessing is used.

What can be done instead is to make use of multiwindow capabilities of each framework. This would require going through documentation of each framework and figuring out how to do it separately for each platform. Ugh.

from pywebview.

cuibonobo avatar cuibonobo commented on May 18, 2024

I was assuming that would be the case anyway :)

I'm going to try getting this working on a Mac and then add on the other platforms as I start figuring it out.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

This is a neat approach. I have to think it through first, though. One problem with this implementation is that there is no way to control child windows and all the pywebview functions point to the master window. While this is not a problem for file dialogs, it would be nice to have an ability to destroy, change urls and load html for child windows programmatically. One way to solve this problem would be to introduce an optional instance_id parameter to these functions. We would also need a way to obtain ids of opened windows.

@cuibonobo what's your use case for having multiple windows?

from pywebview.

cuibonobo avatar cuibonobo commented on May 18, 2024

I got pulled to a different project so I haven't had time to get back to this, but my specific use-case is for an application that has a kind of controller window that serves many child document windows. An example of this would be a painting application where the controller window allows you to pick tools and the document windows is where the actual painting happens.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

I should say a multi-windowed UI is a pretty common use case. Front-end
developers naturally expect at least <a target="_blank"> to work in a web page.
Currently it appears as if it's broken. My best intentions were just to fix this, and
I spotted this issue open. Of course pywebview is not a re-placement for the
browser, but what if someone wants to use it to indeed build a browser? 😉

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

@r0x0r Your suggestion is definitely reasonable. So I have been experimenting with
an instance_id parameter for the API calls. It's working fine under normal use, but
I have spotted some potential bugs.

Still, managing the child windows via JavaScript (open, location.href,close,
etc.) seems to be a better option. The native API should exist, should a user need
them.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Well it turns out to be a little clumsy. I did it the natural way: use the list indices of
BrowserView.instances as our instance_id's, and access each instance via the
usual instances[instance_id] within the API functions. While it works well, it's not
a good approach as it requires the user to keep track of the number of each window
opened by JS. JS can internally keeps a ref to all windows it opens, but I can't see
any way to translate this to our Python instance_id.

For now I have settled with a less functional but cleaner solution: route all API calls
to the key window (the one that currently has user focus) instead of the master
window. IMHO this seems to be enough for the requirements. If it sounds good,
feel free to check out my latest commit.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Great! Meanwhile I hope you try and port it to the other platforms.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

About the windowspec string in Cocoa:

We don't seem to have access to it. In fact we don't even have access to the request
that opens new windows
.

But there is no need. We shouldn't care, because Cocoa/WebKit somehow magically
handles the windowspecs automatically. The only drawback is that it supports only
those properties supported by Safari (basically height,width, left, top; see
Parameter Values -> specs here). Screenshot:

screen shot 2017-05-09 at 8 43 52 pm

But this is expected behaviour. Can't complain; Cocoa does it for us. 😃

Is the work for multi-window support in other platforms on? I'm focusing on Cocoa
only because I haven't got a Windows machine. Could have helped on Linux, but I
would need to learn GTK/QT from ground up. Let me see if I get time..

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

I'm working on multi-window support in GTK. Added basic support, testing.
Not ready for push, there are a couple of bugs. Hope to tackle them soon.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

I briefly took a look at the Windows implementation and it seems that WinForms does not support new window events directly, but instead the NewWindow3 event of Win32 should be used. The problem is that I still haven't managed to call Win32 code from pythonnet (casting interfaces is the root problem). So this might take a while to figure it out.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Sorry for getting late on this, got busy with other stuff. Nevertheless I had been
working on it occasionally. I should say our original (ambitious) approach turned
out to be more cumbersome than I had imagined. It's a long story; the essence is
I couldn't find a good way to control windows opened by JS from Python. We had
discussed this, and I decided to use the JavaScript window.name parameter to
address the instances cross-language, but w/o much success, owing to the quirks
with the WebKit API needed to do this. For now, I have dropped my attempts on it.

Instead, I have been trying out a simpler approach lately and it has given me far
better results. The basic idea is to make the create_window function thread-safe
so that it can be called multiple times via subthreads. create_window returns a
unique instance id, which can be used to point the API functions to the instances.

I have done the basic implementation and testing on Mac and Linux (both GTK &
Qt); I'm pushing a new multi-window branch with my work that is also upto date
with master. I am also deleting the old multiple-windows-support branch from
upstream as it has grown stale; most of the basic ideas used on it are retained in
the new approach as well. I've maintained a local copy of those commits, in case.

It needs to be tested extensively, @cuibonobo can you spare some minutes and
give some feedback? We also need a Windows implementation @r0x0r 🙂 and
your thoughts?

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

Good work, @shivaprsdv ! I gave it a cursory look and the interface looks fine to me, we can go with that. Some minor questions/issues that I could think of

  1. How about making instances a dictionary, as every windows has got its own unique id anyway. This way _get_item would not be needed
  2. Is there a special relationship between master and child windows in this implementation? E.g. should the program quit when the master window is closed?
  3. Window naming. Maybe child windows should have more friendly names, like 'child_truncateduuid'. Not sure if window names will be looked by human eyes, but in case they are (as in debugging), it would be nice to have a more friendly name.
  4. With multiple windows, it would be nice to have windows without chrome, i.e. content only windows with easy move functionality. This is by no means something we should have at this point, but rather something for the future.

It is a big change, so we have to carry on carefully with it. I will give it more thorough testing and will proceed from there.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Thank you @r0x0r. 🙂 Glad that the approach appealed to you.

Great suggestions as well, I have looked into each:

  1. This appealed to me right away, implemented at once (this makes the last
    commit useless, so I have rebased it).

  2. There is currently no special status to the master window (except for its
    uid, of course). The program is set to quit when all windows are closed.
    This can be altered with little effort; so we may let the user decide on this
    behaviour. I can think of two ways:

    • Add an appropriate boolean parameter to webview.config; or
    • Give an API method to check if the master window exists at any time.

    The latter seems better to me. A window_exists(uid) method would be
    handy anyway, as you suggested. The user can then do something like:

    while webview.window_exists('master'):
        pass
    # master closed, close all windows, clean up if needed

    from a subthread. If the above signature is okay, shall I implement it?

  3. This is something I have felt as well. I'm looking for the best way to
    truncate UUIDs. Will do once I find a good solution.

  4. By a chrome-less window, do you mean a window without a titlebar?
    I don't know if such windows are supported on all platforms.

As I have mentioned, this feature solves many other issues as well. So I
think it should be given some priority. More testing and feedback would
definitely help. 👍

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Done implementing 2 and 3 above.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

@shivaprsdv could you rebase this branch? I will start working on it.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

I have merged the latest master into multi-window. I also gave the js_api
feature a test run with the multi-window code; it worked pretty smoothly, no
thing there seems to have broken this. You may build on it straightaway. I hope
we can finish with this before another train of commits on master. 🙂

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

I have pushed the WinForms implementation and some multi-window tests (more to come). @shivaprsdv Could you implement the multi-window support for the rest of platforms? I have merged the latest master into the multi-window branch.

Also refactored tests, which hopefully makes them more robust.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Do we have a misunderstanding? Because I had already implemented multi-window
support on the other platforms. 😃

Anyway I have looked into the changes you have made and made some updates, and
a bit of cleaning up as well. Two things to do:

  1. Currently the multi-window test is not running properly. The issue is, there is
    no destroy event set for the child windows; I have to manually close them. Can
    you fix this? I tried adding the uid param to the destroy_window function in
    utils.py, but couldn't find the best way to proceed from there.

  2. As it is almost merge-ready, we need to add documentation for multi-window
    support. Should I write it?

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

Sorry, I meant the multi-window support for set_title. I merged the set-title branch after your changes.

  1. On Windows the default behavior is to quit the program when the master window is closed. I will change it.
  2. Please go ahead.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

When opening a new window on Cocoa, it places it in exactly the same position as the original window. To prevent obscuring, there should be a offset for new windows.
Specifying window position should probably be added at some point, but a default offset should be enough for now.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Pushed. I had done it in the old branch, can't remember why I left it out from this.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

Nice one.
I've pushed a js bridge multi-window test. I haven't managed to get it passed on Cocoa. assert for the seconds window fails. Another problem is that setting debug to True on both windows freezes the second window.
I am yet to test it on other platforms.

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

I think it has got to do with our old problem of closing child windows: I now have
to close the windows manually again, and the test pass. I suggest you look into
whether destroy_window calls are done properly.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

Cocoa implementation is not thread safe. In particular load_event is a class attribute, when it should be an instance attribute. Currently the multi window js bridge test hangs due infinite waiting for load_event in evaluate_js in the second window. There are also considerable lags with every evaluate_js call, I suspect that webview_ready is timing out, instead of returning right away.

Other than that, refactored assert_js, as well as implemented conversion to Python types of values returned by evaluate_js in Cocoa. It also occurred to me that Javascript objects should be converted to Python dicts, but this is a job for another time.

from pywebview.

r0x0r avatar r0x0r commented on May 18, 2024

I have fixed Cocoa among other changes. Test seem to pass, apart from random fails on Python2/GTK. I could not reproduce fails locally, so let it be for the time being. It seems that the test infrastructure requires an overhaul.
Apart from the documentation, this is ready for merge. What do you think @shivaprsdv?

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

Great! Especially good to see tests passing on Cocoa, after some time. I have
pushed the documentation; I tried to keep it to the minimum, feel free to modify
it as you find appropriate.

BTW it would be useful to expose the uid of the window to the JS API. But this
means we need to create the API object regardless of the user passing a js_api
parameter. Only if it is a light task, could be done before merge. Otherwise let's
keep it for post-merge. Everything else looks fine. 👍

from pywebview.

shivaprsd avatar shivaprsd commented on May 18, 2024

@cuibonobo Starting from your idea, pywebview now have full multiple windows
support. Please check it out. And thanks for your input! 🙂

from pywebview.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.