VMware

Time to rethink GTK+ Tab Dragging

I’ve been planning on adding tab drag-and-drop functionality to VMware Workstation 6.0. Rather than implementing this ability from scratch (which I did with Gaim, and would rather not do again), I took the sane approach and started investigating the GTK+ 2.10 API for GtkNotebook tab drag-and-drop.

This is functionality that many applications have had to implement themselves, so it’s great that support had finally gone into GTK+ 2.10. So I must wonder, with all the various applications that would benefit from this new API, how did we get it so wrong?

Now, before I continue, let me say that I applaud the effort in getting this into GTK+ in the first place. Reordering tabs looks smooth, it’s only one API call, and the basics are trivial. Where this all falls down is when you try to do anything complicated with it, and by complicated I mean anything beyond a simple text editor.

Before starting, I investigated how many projects were using this API. A quick Google Code search shows that almost nobody does, aside from maybe the tab reordering API. I did find this list of complaints, which I remember reading before. I won’t repeat everything on this list, but I will list what I’ve ran into, and how I think we can improve this API.

Global functions are very bad. (Bug 386935)

In order to allow for a tab to be dragged out and form a new window, the application must call gtk_notebook_set_window_creation_hook and pass a callback function. When a tab marked as detachable is dragged to the root window, this function will be called. It is expected that the function create a new window, position it as per the x and y coordinates of the drop (if it so desires), show it, and return the resulting notebook. GTK+ will then add the tab to that notebook.

While useful, this suffers from a major design flaw. You can’t set a window creation hook per-notebook. You get exactly one window creation hook function, which must be responsible for any and all notebooks in the program. The hook function can only distinguish between them using the notebook’s group ID.

For smaller programs, this isn’t a huge limitation. Simple text editors and the like only need one function. However, imagine if your application has multiple notebooks that each need to be dragged, and imagine if the code for those notebooks are in two separate parts of the tree. Maybe you have a nice separation of the different parts of the project. Regardless, now you have to have one common function that knows about both and handles their window creations.

The problem gets far worse for applications separated into different libraries, or those using widget utility libraries. Two separate libraries both providing a notebook with drag-and-drop with their own window creation won’t be able to set up a hook. They would require that the main application handle determining the group IDs of the notebook widgets they care about and then calling the proper functions in the libraries. While doable, it’s a horrible burden on the application, and it doesn’t always work.

Of course, the whole thing completely breaks down when you’re writing a plugin with a notebook rather than an application. The plugin won’t be able to offer its own window creation, due to possible conflicts with the main application and other plugins.

The solution, of course, is to have per-notebook window creation hooks. GTK+ could attempt to call one of these and then fall back to the global hook, if it exists. If calling the global hook, GTK+ could spit out a warning informing the user that the program should be upgraded to the new API and that the existing method is deprecated.

Rather than functions, though, a signal handler may make more sense. It could use a collector and call the handlers until it finds one that returns a GtkNotebook. I could see this being useful if a widget component library (as part of a larger project) provides a default window creation handler that the calling application wants to override for a specific case.

Numeric group IDs lead to namespace collisions. (Bug 386930)

Right now, in order to indicate which notebooks are compatible for drag-and-drop operations, each GtkNotebook gets a group ID. This is an unsigned integer with absolutely no rules on how an ID should be picked. This is very dangerous, as it could cause namespace collisions in larger applications, resulting in tabs being droppable onto incompatible notebooks. This could easily crash such applications.

There’s no reason for us to be using integers. Take a look at GtkRadioButton. They also have groups, but they work a bit differently. The first GtkRadioButton defines the group, and the rest get passed that as the group identifier. In gtkmm, you actually have a Gtk::RadioButtonGroup object that you simply instantiate and then pass to each radio button.

Now, in any well-designed program, there should be only one place creating the notebook for a certain type of window, and usually that’s the only type of notebook capable of accepting tabs from the same class of notebook. So, why not do something like what gtkmm does and have some sort of static object that represents that group, define it once, and pass it to each notebook? This is guaranteed to be unique, and solves the namespace collision issue.

Signals need to be more clear. (Bug 386943)

You can determine if a page was added to a notebook or removed from it, but there’s no clear way of determining if it was due to an API call, or a drag-and-drop operation. We worked around it in VMware Workstation, but it would have been very helpful to know precisely that a page was added due to drag-and-drop. Same with the removed signal. I know they wanted to condense the signals and figured it would work in all cases, but it doesn’t, so please, give us some more specific signals!

Drop operations should be able to be programatically rejected. (Bug 386950)

There are times when you want to allow a tab to be draggable, but want to reject it in notebooks under certain circumstances. For example, in VMware Workstation, we have the “Home” tab. I would like to be able to drag this to empty windows, but if that window has a “Home” tab already, I want to reject the drag. To my knowledge, there is no way to do this currently.

Detaching tabs into new windows requires a drag to the desktop. (Bug 360225)

In most any program with tab drag-and-drop, you can drag a tab off into any area not in the tab bar and it will detach into a new window. With the GTK+ tab dragging, you have to actually drag it to the root desktop. Even dragging off into another window isn’t good enough. This sucks. Let’s fix this properly. We’re not doing anybody any favors.

I’m missing a few annoyances I ran into, but I’ll be blogging about them separately once I remember.

So, to recap, I believe we should:

  • Deprecate gtk_notebook_set_window_creation_hook and add a new create_window signal, returning a GtkNotebook.
  • Ditch the numeric group IDs and use some sort of identifier object or generic pointer to a static variable and pass that in instead.
  • Add new signals or something telling us specifically how the tab was added/removed.
  • Provide a way to reject a tab drop on a particular notebook programatically.
  • Call the window creation hook any time the tab is dragged off the tab portion of the notebook.

It would be great to see these things fixed so that more applications can actually use this API without major headaches. Anyone up for the task?

I plan to put up a new post soon giving a couple of tips for using the current API.

Update: Bugs have been filed for the above. They’re in the topic headers.

Planet VMware, Planet V12n

We officially announced two new planets last night at VMware: Planet VMware and Planet V12n, both powered by Planet.

Planet VMware is a Planet for VMware employees, in the spirit of Planet GNOME and such. There are currently ten VMware bloggers on there. This will of course increase in time.

Planet V12n is designed to be the go-to source for virtualization news. Blogs and sites such as virtualization.info and Virtual Strategy Magazine are included, with news covering all things virtualization, VMware and otherwise. The VMware employee blogs are also shown alongside the virtualization blogs.

The planets are very new, so there’s a couple of bugs to work out. The Planet VMware atom feed is busted right now, but it’s a known problem and will be fixed shortly. Please let us know if there are any other glaring problems.

Gallery Virtual Appliance

Virtual machines used to be all about managing your data center or server consolidation or running applications that only run on some other operating system. Lately, virtual machines have been gaining momentum in a new area: software distribution.

This is actually quite powerful. Instead of a giving a user a complex set of instructions for installing some application or web service, and telling them what they need to install beforehand and what distros or operating systems it works on, the distributor or project can instead provide a bare-bones virtual machine containing the application or service pre-configured, and users can simply download it and power it on. It’s a great way of previewing applications or even running them day-to-day (depending on the application).

There’s a wonderful service out there called Gallery. It’s a web-based photo gallery that users can install on their server in order to share photos with the world. There’s a number of modules available. Many programs work with it. You can do things like order prints through the web. Great program.

And it’s now available in a virtual appliance! They have a description and instructions for setting it up, and I’ve been informed that they plan to keep it updated with each new release. It contains both Gallery 1 and Gallery 2, giving users a chance to see the differences between the versions and decide which suits them best. It can be used in VMware Player, Server, Workstation, and probably ESX (I haven’t tried). It’s downloadable from their website or from VMTN. You can see h0bbel’s blog post for more information on the appliance.

I think this is awesome and I hope it works out well for them and for the users. I’d love to see more projects go this route, and with any luck, Gallery will have set a precedent in the web services world. And for the developers creating these appliances, please feel free to let us know what VMware could do to make your lives easier. We welcome feedback, and you can send it directly to me.

VMware Server 1.0 Released

As most people have probably seen on Slashdot or Digg by now, we just released VMware Server 1.0. As promised, it is a free product and should run your virtual machines much faster than the earlier betas did.

(If you’re not sure what VMware Server is all about, please read my original post.)

VMware Server has already been deployed at several companies ever since beta 1. I’ve always found that amusing, given how young the product was at that stage (even though this is essentially GSX 4). However, my experience in talking to beta testers so far is that most people are pretty happy with the product, especially given the price. I am personally running it at home for my Linux development VMs and it has been working nicely.

My thanks go out to all the testers that have reported problems or who have given us feedback of any kind. As one of the developers on VMware Server, it has been nice hearing positive reports and stories :).

Bocce Ball

The VMware Hosted UI group (the group I’m a part of) went on a team-building exercise today. We had a nice meal and then went to play Bocce Ball, which is a game that until today I had very little knowledge of. It turns out to be a pretty cool game, with some strategy involved. Our team kicked ass 😉 I’m actually hoping to play again at some point soon. Perhaps we can buy some Bocce Balls and play in the hallways by our new offices.

Oh, yeah, so we moved offices at work. My nice corner office is no longer mine. However, the new office is actually bigger, and the view isn’t too bad. I’ve only spent a few hours in it so far, but it’s not as bad as I feared. I’ll have to take pictures soon.

Lost my hacking mojo

I’ve been trying to get out of this funk I’ve been in the past few weeks. It’s been far too hard to just sit down and code outside of work. I can’t even put together a release. A large part of this is due to the amount of work I’ve been doing for VMware as of late on VMware Server. I think another part of it is that I recently finished up releases of Galago, libnotify, notification-daemon, and Leaftag and

I know this is temporary, but it’s frustrating because there really is a lot of cool stuff I’m looking forward to working on. Some may say to enjoy it, take a break, play some games. Problem is, I don’t even feel like doing that! 😛 Perhaps after work calms down and I’ve spent long enough doing nothing at home, I’ll have more motivation to code.

How do other people usually deal with this?

The Big 22

Okay, I don’t know how big it is, but I’m 22 today! Now I can, um, get drunk? No, that was last year. Hmm. Okay, so 22 isn’t special. It’s just one day closer to 30. Still, today should be a very fun day. My girlfriend is coming to visit, I have some presents to open, and I bought some good movies to watch.

Yesterday was fun as well. My team at work treated me to sushi at my favorite sushi restaurant (Fuki Sushi). We sat in one of those Tatami rooms (where you take your shoes off and sit on the ground), which I’ve always wanted to try. Later we played Tetrinet for a bit, and then I took off with my dad. We got some dinner, watched Sahara, and then called it a night.

I’ve spent most of today looking online for old Zelda and Mario comics. I’m quite pleased to find a large selection of scans 🙂 If anyone has any resources for Mario comic scans, I’d love to see them.

For all those people who just love me so much and have nothing better to do with their money, I’ve posted a small wishlist up 😉 You know you want to.

And now it’s about time to take off and meet my girlfriend at the train station.

Goings Ons

Hard Day in GNOME

All day long, people have been talking on IRC about the Novell lay-offs. It’s been sad to see, and as hard as it was for the people who were let go, I’m sure it was just as hard for those that had to let people go. My condolences to everyone who’s been affected by this.

I’ve talked to a few people individually about this, but it’s been recommended to me by a couple of people that perhaps using Planet GNOME would be the best way to reach everyone interested…

I’d like to offer to anyone affected by this who is looking for a job to send me your resume if you’re interested in a job at VMware. I can make sure it goes to a human being who will actually read it, rather than in some queue somewhere. We’re looking for good people, and the company is nice to work at. Although the Palo Alto offices are where all the interesting things happen for the Linux desktop development, some jobs are available at our new Cambridge office. So if you’re looking for a fun job where you can do interesting work with good people, and this interests you, even a little, we can try to get the ball rolling. To everyone else, best of luck. I don’t doubt that you will all find good jobs soon, and everyone appreciates what has been done so far by everyone in the Ximian team.

Nokia 770

My Nokia 770 came today. I haven’t had much time to play with it, but it’s quite nice so far. Cute little device, and I’m eager to hack on it. I have a couple of games I’ve written or PDAs that I hope to port. Taco would be fun to port to it, if it had cairo (which I don’t believe it does? Correct me if I’m wrong!).

Galago

A lot of work has been done in Galago SVN the past couple of weeks. A lot of the code has been cleaned up and the API is in the process of being fine-tuned. Python bindings are being written. libgalago is moving to glib. All neat stuff. I’ll post more when I get closer to being finished, but this is very cool:

for service in galago.core_get_services():
    print service.get_name()
    for account in service.get_accounts():
        print account.get_username()

Just so easy. That’s not the final API, though. The core_get_services() part will change. Anyhow, fun stuff.

Sometimes you’re the windshield, sometimes you’re the bug

This weekend has been generally not a good weekend, but up until now, it was just annoying, not problematic. I guess it’s not that problematic, but well…

I’m sleeping at work tonight.

I decided to do one simple thing tonight. I would walk out of my apartment and get Chinese food from the restaurant right next to my apartment. It’s like a 2 minute walk from my door, if that. No big problem, right?

First, I need to grab the wallet. This is important, as I must pay. Keys, hmm.. Nah, don’t need keys, I’m only going next door. I’ll be back in 10 minutes. Open the door, lock it, close it behind me. Wait, lock it? CRAP!

So I called the main office for the company that owns the apartment complex. Turns out they’re stationed in Texas, are are evacuated at the moment. Goody. Fortunately, they had backups. Lots and lots of unconnected backups. I reached one of them, no clue where it was, and they said I can expect a call soon from someone at my complex who could unlock my door. Great! I’ll just wait then.

45 minutes pass.

Called again, got someone else in a completely different state. She explained the whole problem, and the process for getting my door unlocked. First, a person at one of these offices sends an e-mail to someone at some other office. An e-mail. Great. Hurray for instant communication. Eventually, someone gets that e-mail, picks a person from the apartment complex in question, and calls.

Now, one of these two things didn’t work out so well, as it was almost three hours before I gave up. I decided to head to work and just get work done overnight, and sleep during Monday afternoon.

Next time I’ll know better than to think, “Keys? Nah, I don’t need keys!”

Scroll to Top