Monday, April 28, 2008

XEmacs is Dead. Long Live XEmacs!

 "We're going to get lynched, aren't we?" — Phouchg


And you thought I'd given up on controversial blogs. Hah!

Preamble

This must be said: Jamie Zawinski is a hero. A living legend. A major powerhouse programmer who, among his many ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r accomplishments, wrote cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original Netscape Navigator and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original XEmacs. A guy who can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 term "downward funargs" and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n glare at you just daring you to ask him to explain it, you cretin. A dude with arguably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best cat-picture blog ever created.

I've never met him, but I've been in awe of his work since 1993-ish, a time when I was still wearing programming diapers and needing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m changed about every 3 hours.

Let's see... that would be 15 years ago. I've been slaving away to become a better programmer for fifteen years, and I'm still not as good — nowhere near as good, mind you — as he was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n. I still marvel at his work, and his shocking writing style, when I'm grubbing around in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 guts of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emacs-Lisp byte-compiler.

It makes you wonder how many of him cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re. You know, programmers at that level. He can't be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only one. What do you suppose cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're all working on? Or do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y all eventually make 25th level and opt for divine ascension?

In any case, I'm sad that I have to write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 obit on one of his greater achievements. Sorry, man. Keep up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cat blog.

Forking XEmacs

I have to include a teeny history lesson. Bear with me. It's short.

XEmacs was a fork of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GNU Emacs codebase, created about 17 years ago by a famous-ish startup called Lucid Inc., which, alas, went Tango Uniform circa 1994. As far as I know, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir two big software legacies still extant are a Lisp environment now sold by LispWorks, and XEmacs.

I'd also count among cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir legacies an absolutely outstanding collection of software essays called Patterns of Software, by Lucid's founder, Richard P. Gabriel. I go back and re-read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m every year or so. They're that good.

Back when XEmacs was forked, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re were some fireworks. Nothing we haven't seen many times before or since. Software as usual. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was a Great Schism. Nowadays it's more like competing football teams. Tempers have cooled. At least, I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have.

As for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole sordid history of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FSF-Emacs/XEmacs schism, you can read about it online. I'm sure it was a difficult decision to make. There are pros and cons to forking a huge open-source project. But I think it was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right decision at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time, just as decomissioning it is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right decision today, seventeen years later.

XEmacs dragged Emacs kicking and screaming into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modern era. Among many ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r things, XEmacs introduced GUI widgets, inline images, colors in terminal sessions, variable-size fonts, and internationalization. It also brought a host of technical innovations under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hood. And XEmacs has always shipped with a great many more packages than GNU Emacs, making it more of a turnkey solution for new users.

XEmacs was clearly an important force helping to motivate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 evolution of GNU Emacs during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mid- to late-1990s. GNU Emacs was always playing catch-up, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dev team led by RMS (an even more legendary hacker-hero) complained that XEmacs wasn't really playing on a level field. The observation was correct, since XEmacs was using a Bazaar-style development model, and could move faster as a direct consequence.

A lot of people were switching over to XEmacs by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mid-1990s: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fancy widgets and pretty colors attracted GNU Emacs users like moths to a bug-zapper.

Problem was, it could actually zap you.

The downside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bazaar

I personally tried to use XEmacs many times over a period of many years. I was jealous of its features.

However, I never managed to use XEmacs for very long, because it crashed a lot. I tried it on every platform I used between ~1996 and 2001, including HP/UX, SunOS, Solaris, Ultrix, Linux, Windows NT and Windows XP. XEmacs would never run for more than about a day under moderate use without crashing.

I've argued previously that one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most important survival traits of a software system is that it should never reboot. Emacs and XEmacs are at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leading edge of living software systems, but XEmacs has never been able to take advantage of this property because even though it can live virtually forever, it's always tripping and falling down manholes.

Clumsy XEmacs. Clumsy!

I assume its propensity for inopportune heart attacks is a function of several things, including (a) old-school development without unit tests, (b) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 need to port it to a gazillion platforms, including many that nobody actually uses, (c) a culture of rapid addition of new features. There are probably ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r factors as well.

I'm just speculating though. All I know is that it's always been very, very crashy. It doesn't actually matter what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reasons are, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's no excuse for it.

Interestingly, most XEmacs users I've talked to say cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't notice cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crashing. I'm sure this is because it's all relative. XEmacs doesn't crash any more often than Firefox, for instance. Probably less often. When Firefox crashes I make a joke about it and restart it, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crashing rarely has an impact. It even restores your state properly most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time, so it's just a minor blip, an almost trivial inconvenience, so long as whatever text field you happen to be editing has an auto-save feature. And most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 good ones do.

XEmacs may crash even less than Eclipse and IntelliJ. Crashing editors usually aren't a big problem. Programmers all learn cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hard way to save cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir buffers frequently. For me, saving is like punctuation; I save whenever my typing pauses, out of reflex. Doesn't matter whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it's Emacs or NeoOffice or GMail or... do I use any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r apps? Oh yeah, or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Gimp. When I pause, I save, and if you're a programmer I bet you do too. So occasional crashes may seem OK.

Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r reason cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crashes aren't called out more often is that most Emacs and XEmacs users are at best casual users. They open up an {X}Emacs session whenever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y need to edit a file, and close it when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're done. It's just Notepad with colors and multi-level Undo.

If your average session length is shorter than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 editor's MTBF, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n yeah, you're not going to notice much crashing.

In contrast, your more... ah, seasoned (read: fanatical) Emacs users gradually come to live in it. Anything you can't do from within Emacs is an annoyance. It's like having to drive to a government building downtown to take care of some random paperwork cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y should have been offering as an online service a decade ago. You can live with it, but you're annoyed.

Even Firefox, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r big place I live, really wants to be Emacs. Tabs don't scale. Tabbed browsing was revolutionary in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way adding more tellers to a bank was revolutionary: it's, like, 4x better. w00t. Emacs offers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unique ability to manage its open buffers in anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r first-class buffer, as a list. Imagine what your filesystem life would be like if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only view of a directory was one tab per file. Go to your pictures directory and watch it start vomiting tabs out like it tried to swallow a box of chiclets. Fun!

I feel sad when I see Eclipse users with fifty open tabs, an army of helpful termites eating away at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir screen real-estate and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir time.

I have a feeling I've veered off course somewhere... where was I? Oh yeah. Crashing.

So XEmacs has never been a particularly good tool for serious Emacs users because even though it's written in C, it crashes like a mature C++ application. You know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 drill: major faceplants, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fugging time.

Your ability to become an inhabitant of Emacs is gated by how stable it is. GNU Emacs has always been famously stable. Sure, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 releases happen less frequently than presidential inaugurations. Sure, for a long time it always lacked some XEmacs feature or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. But it's really, really stable. Its MTBF is measurable in weeks (or even months, depending on what you're doing with it) as opposed to hours or days.

Emacs, like Firefox, can be configured to back up your state periodically, so that in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory it can recover after a crash. That's part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem: you didn't actually have to configure Firefox to get that behavior. It does it automatically. And to be honest, I've never had much luck with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emacs save-state facilities. I'm a pretty competent elisp hacker cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se days, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 desktop.el has never worked reliably for me. I could probably get it to work, but I've always found it easier to write specialized startup "scripts" (lisp functions) that load up particular favorite configurations.

If I can't get desktop-save working, I'd guess that fewer than 1/10th of 1 percent of Emacs users use that feature. So crashes blow everything away.

If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 state isn't being auto-saved, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next best thing is for it not to crash.

XEmacs never got that right.

Don't get me wrong...

I just realized I'm going to get screamed at by people who think I'm just an XEmacs-hater slash GNU-fanboy.

Make no mistake: I'm a fan of XEmacs. I think it was a great (or at least, necessary) idea in 1991. I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 execution, aside from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stability issue, was top-notch. I think it had a good architecture, by and large, at least within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r severe constraints imposed by Emacs Lisp. I think it spurred competition in a healthy way.

I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XEmacs development team, over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 years, has consisted of engineers who are ALL better than I am, with no exceptions. And I even like certain aspects of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interface better, even today now that GNU Emacs has caught and surpassed XEmacs in features. For instance, I like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XEmacs "apropos" system better.

If you're going to scream at me for irrational reasons, it really ought to be for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right irrational reasons. Legitimate dumb reasons for screaming at me include: you're lazy and don't want to learn anything new; you invested a lot of time in XEmacs and don't see why you should be forced to switch; you are a very slow reader, causing you to skip three out of every five words I write, resulting in your receipt of a random approximation of my blog content, with a high error bar; you're still mad about my OS X blog. All good bad reasons.

Heck, you could even scream for rational reasons. Perhaps you have a philosophical beef with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FSF or GPL3. Perhaps XEmacs still has some vestiges of feature support that do not yet exist in GNU Emacs, and you truly can't live without cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. I would think you're being a teeny bit uptight, but I would respect your opinion.

Whatever you do, just don't yell at me for thinking I'm dissing XEmacs or taking some sort of religious stance. Far from it. I just want a unified Emacs-o-cratic party.

XEmacs vs. GNU Emacs today

GNU Emacs pulled into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lead in, oh... I'd say somewhere around maybe 2002? 2003? I wasn't really keeping track, but one day I noticed Emacs had caught up.

Even today I maintain XEmacs/FSF-Emacs compatibility for my elisp files – some 50k lines of stuff I've written and maybe 400k lines of stuff I've pilfered from EmacsWiki, friends, and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r sources. I still fire up XEmacs whenever I need to help someone get un-stuck, or to figure out whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r some package I've written can be coerced to run, possibly in restricted-feature mode, under XEmacs.

For years I chose stability over features. And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n one day GNU Emacs had... well, everything. Toolbars, widgets, inline images, variable fonts, internationalization, drag-and-drop in and out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS clipboard (even on Windows), multi-tty, and a long laundry-list of stuff I'd written off as XEmacs-only.

And it was still stable. Go figure.

I don't have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full feature-compatibility list. Does it even exist? You know, those tables that have little red X's if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Evil Competitor product is missing some feature your product offers, and little green checkmarks, and so on. We ought to make one of those. It would be useful to know what (if any) XEmacs features are preventing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last holdouts from migrating to FSF Emacs.

But for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past five years or so, just about every time an XEmacs user on a mailing list has mentioned a feature that's keeping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m from switching, it's been solved.

If GNU Emacs isn't a perfect superset of XEmacs yet, I'm sure we could get it cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re if we had cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 big unified-platform carrot dangling in front of us. And I bet it's pretty close already.

Features and stability aside, XEmacs is looking pretty shabby in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 performance department. Its font-lock support has never been very fast, and a few years back GNU Emacs took a giant leap forward. XEmacs can take 4 or 5 seconds or longer to fontify a medium-sized source file. Sure, it shows that big progress bar in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 middle of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen, so you know it's not dead, but when you're used to it being almost instantaneous, coming back to XEmacs is a real shocker.

And XEmacs has bugs. Man, it has a lot of bugs. I can't begin to tell you how many times I've had to work around some horrible XEmacs problem. It has bugs (e.g. in its fontification engine and cc-engine) that have been open for years, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can be really painful to work around. I've had to take entire mode definitions and if-xemacs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, using an ancient version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mode for XEmacs because nothing even remotely recent will run.

You may not notice cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs, but as elisp developers, we feel cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pain keenly.

Fundamental incompatibilities

As if issues with stability, performance and bugs weren't enough, XEmacs has yet anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r problem, which is that its APIs for dealing with UI elements (widgets and input events, but also including things like text properties, overlays, backgrounds and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r in-buffer markup) are basically completely different from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir GNU-Emacs counterparts. The two Emacsen share a great deal of common infrastructure at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Lisp level: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have mostly compatible APIs for dealing with files, buffers, windows, subprocesses, errors and signals, streams, timers, hooks and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r primitives.

But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir APIs range from mildly to completely different for keyboard and mouse handling, menus, scrollbars, foreground and background highlighting, dialogs, images, fonts, and just about everything else that interfaces with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window system.

The GUI and display code for any given package can be a significant fraction of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total effort, and it essentially has to be rewritten from scratch when porting from GNU Emacs to XEmacs or vice-versa. Unsurprisingly, many package authors just don't do it. The most famous example I can think of is James Clark's nxml-mode, which claims it'll never support XEmacs. I found that pretty shocking, since I thought it was basic Emacs etiquette to try to support XEmacs, and here James was cutting all ties, all public about it and everything. Wow.

But I totally understand, since I really don't want to rewrite all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 display logic for my stuff eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r.

I'll be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first to admit: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API discrepancies are not XEmacs's fault. I can't see how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y could be, given that for nearly all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se features, XEmacs had cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m first.

For a developer trying to release a productivity package, it doesn't really matter whose fault it is. You target cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 platform that will have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most users. I don't know what XEmacs's market share is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se days, but I'd be very surprised if it's more than 30%. That's a big number, but when you're an elisp hacker creating an open-source project in your limited spare time, that number can start looking awfully small. Teeny, even.

XEmacs should drop out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 race

At this point it's becoming painful to watch. GNU Emacs is getting all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 superdelegates. That warmonger VIM is sitting back and laughing at us. But XEmacs just won't quit!

I'm sure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few old-timers out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re who still care about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bad blood that originally existed between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two projects. To everyone else it's ancient history. As far as I can tell, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re has been an atmosphere of polite (if subdued) cooperation between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two projects. Each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m has incorporated some compatibility fixes for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, although it's still mostly up to package authors to do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heavy lifting of ensuring compatibility, especially for display code.

I haven't seen any XEmacs/GNU-Emacs flamewars in a long time, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. We're all just *Emacs users, keeping our community alive in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 face of monster IDEs that vomit tabs, consume gigabytes of RAM, and attract robotic users who will probably never understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 critical importance of customizing and writing one's own tools.

When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Coke/Pepsi discussion comes up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se days, it's usually an XEmacs user asking, in all seriousness, whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y should transition to GNU Emacs, and if so, would someone volunteer to help migrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir files and emulate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir favorite behaviors.

Yes, someone will volunteer. I promise.

The dubious future of Emacs

I've got good news and bad news.

The good news is: Emacs is a revolutionary, almost indescribably QWAN-infused software system. Non-Emacs users and casual users simply can't appreciate how rich and rewarding it is, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have nothing else to compare it to. There are ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r scriptable applications and systems out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re — AppleScript, Firefox, things like that. They're fun and useful. But Emacs is self-hosting: writing things in it makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 environment itself more powerful. It's a feedback loop: a recursive, self-reinforcing, multiplicative effect that happens because you're enhancing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 environment you're using to create enhancements.

When you write Emacs extensions, sometimes you're automating drudgery (always a good thing), sometimes you're writing new utilities or apps, and sometimes you're customizing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behavior of existing utilities. This isn't too much different from any well-designed scriptable environment. But unlike in ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r environments, sometimes you're improving your editing tools and/or your programming tools for Emacs itself. This notion of self-hosting software is something I've been wanting to blog more about, someday when I understand it better.

Eclipse and similar environments want to be self-hosting, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're not, because Java is not self-hosting. In spite of Java's smattering of dynamic facilities, Java remains as fundamentally incapable of self-hosting as C++. Self-hosting only works if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code can "fold" on itself and become more powerful while making itself smaller and cleaner. I'm not really talking about macros here, even though that's probably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first thing you thought of. I'm thinking more along cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lines of implementing JITs and supercompilers in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hosted runtime, racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C++ or Java "hardware" substrate, which is where everyone puts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m today.

I suspect (without proof) that in self-hosted environments, you can eventually cross a threshold where your performance gains from features implemented in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hosted environment outpace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 gains from features in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 substrate, because of this self-reinforcing effect: if code can make _itself_ faster and smarter, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it will be faster and smarter at making itself faster and smarter. In C++ and Java, making this jump to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 self-reinforcing level is essentially intractable because, ironically, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have so many features (or feature omissions) for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sake of performance that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y get in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own way.

To be sure, Emacs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current crop of popular scripting languages, and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r modestly self-hosting environments are all pretty far from achieving self-reinforcing performance. But Emacs has achieved it for productivity – at least, for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relatively small percentage of Emacs users who learn enough elisp to take advantage of it. There are just enough of us doing it to generate a steady supply of new elisp hackers, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 general-purpose artifacts we produce are usually enough to keep cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current crop of casual users happy.

The bad news: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 competition isn't cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IDEs

I've argued that Emacs is in a special self-reinforcing software category. For productivity gains, that category can only be occupied by editors, by definition, and Emacs is currently way ahead of any competition in most respects. So most Emacs users have felt safe in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 assumption that IDEs aren't going to replace Emacs.

Unfortunately, Emacs isn't immunized against obsolescence. It still needs to evolve, and evolve fast, if it's going to stay relevant. The same could be said of any piece of software, so this shouldn't be news. But it's particularly true for Emacs, because increasing numbers of programmers are being lured by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 false productivity promises of IDEs.

They really are false promises: writing an Eclipse or IntelliJ (or God help you, Visual Studio) plugin is a monumental effort, so almost nobody does it. This means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's no community of building and customizing your own tools, which has long been cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hallmark of great programmers. Moreover, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effort to create a plugin is high enough that people only do it for really significant applications, whereas in Emacs a "plugin" can be any size at all, from a single line of code up through enormous systems and frameworks.

Emacs has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same learning-curve benefit that HTML had: you can start simple and gradually work your way up, with no sudden step-functions in complexity. The IDEs start you off with monumental API guides, tutorials, boilerplate generators, and full-fledged manuals, at which point your brain switches off and you go over to see what's new on reddit. ("PLEASE UPMOD THIS PIC ITS FUNNY!")

And let's not even get into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Million Refactorings yet. It's a blog I've been working on for years, and may never finish, but at some point I'd like to try to show IDE users, probably through dozens or even hundreds of hands-on examples I've been collecting, that "refactoring" is an infinite spectrum of symbol manipulation, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have, um, twelve of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. Maybe it's thirteen. Thirteen out of infinity – it's a start!

Programmers are being lured to IDEs, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current crop of IDEs lacks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 necessary elements to achieve self-hosting. So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only damage to Emacs (and to programmers in general) is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bar is gradually going down: programmers are no longer being taught to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own tools.

IDEs are draining users away, but it's not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 classic fat-client IDEs that are ultimately going to kill Emacs. It's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browsers. They have all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 power of a fat-client platform and all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flexibility of a dynamic system. I said earlier that Firefox wants to be Emacs. It should be obvious that Emacs also wants to be Firefox. Each has what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r lacks, and togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're pretty damn close to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ultimate software package.

If Emacs can't find a way to evolve into (or merge with) Firefox, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n Firefox or some ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r extensible browser is going to eclipse Emacs. It's just a matter of time. This wouldn't be a bad thing, per se, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's a good chance it would be done poorly, take forever, and wind up being less satisfying than if Emacs were to sprout browser-like facilities.

Emacs as a CLR

So Emacs needs to light a fire and hurry up and get a better rendering engine. Port to XUL, maybe? I don't know, but it's currently too limited in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application domains it can tackle. I realize this is a very hard problem to solve, but it needs to happen, or at some point a rendering engine will emerge with just enough editing power to drain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 life from Emacs.

Emacs also needs to take a page from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JVM/CLR/Parrot efforts and treat itself as a VM (that's what it is, for all intents) and start offering first-class support for ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r languages. It's not that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's anything wrong with Lisp; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem is X programmers. They only want to use X, so you have to offer a wide range of options for X. Emacs could be written in any language at all, take your pick, and it wouldn't be good enough.

RMS had this idea a long, long time ago (when he was making cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r controversial point that Tcl isn't a valid option for X), and it eventually led to Guile, which led more or less nowhere. Not surprising; it's a phenomenally difficult challenge. There are really only two VMs out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re that have achieved even modest success with hosting multiple languages: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CLR and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JVM. CLR's winning that race, although it's happening in a dimension (Windows-land) that most of us don't inhabit. Parrot is... trying really hard. Actually, I should probably mention LLVM, which (like Parrot) was designed from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ground up for multi-language support, but took a lighter-weight approach. So let's call it four.

In any case, it's a small very group of VMs, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y still haven't quite figured out how to do it: how to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 languages to interoperate, how to get languages ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first to perform decently, and so on.

This is clearly one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hardest technical challenges facing our industry for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next 10 years, but it's also one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most obviously necessary. And Emacs is going to have to play that game. I'm not talking about hacked-togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r process bridges like PyMacs or el4r, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r — I mean first-class support and all that it entails.

I've mentioned cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rendering engine and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 multi-language support; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last major hurdle is concurrency. I don't know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 answer here, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, but it needs an answer. Threads may be too difficult to support with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current architecture, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r options, and someone needs to start thinking hard about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. Editing is becoming a complicated business — too complicated for hand-rolling state machines.

Compete or die

So Emacs has some very serious changes ahead.

Let's face it: we're not going to see real change unless ALL cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emacs developers out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re – today's crop of JWZs – band togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to make it happen. But today we're divided. Two groups of brilliant C hackers working on separate, forked code bases? That's bad. Two groups of maniacal elisp hackers working on incompatible packages, or at best wasting time trying to achieve compatibility? Also bad.

Developers are starting to wake up and realize that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best "mainstream" extensible platform (which excludes Emacs, on account of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Lisp) is Firefox or any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r non-dead browser (which excludes IE). Dynamic typing wins again, as it always will. Dynamic typing, property-based modeling and non-strict text protocols won cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 day for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 web, and have resisted all incursions from heavyweight static replacements. And somehow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 web keeps growing, against all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 predictions and lamentations of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 static camp, and it still works. And now cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browsers are starting to sprout desktop-quality apps and productivity tools. It won't be long, I think, before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best Java development environment on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 planet is written in JavaScript.

Emacs has to compete or die. If Firefox ever "tips" and achieves even a tenth of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 out-of-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-box editing power of Emacs, not just for a specific application but for all web pages, widgets, text fields and system resources, Emacs is going to be toast. I may be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last rat on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ship, but I'm sure not going down with it; even _I_ will abandon Emacs if Firefox becomes a minimally acceptable extensible programmer's editor. This is a higher bar than you probably think, but it could happen.

We no longer need XEmacs to spur healthy competition. The competition is coming in hard from entirely new sources. What we need now is unity.

Then why not unify behind XEmacs?

I threw this in just in case you blew through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 article, which I'd find perfectly understandable. To summarize, I've argued that XEmacs has a much lower market share, poorer performance, more bugs, much lower stability, and at this point probably fewer features than GNU Emacs. When you add it all up, it's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 weaker candidate by a large margin.

Hence cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's only one reasonable strategy: Hill, er, I mean XEmacs has to drop out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 race.

I'm really sorry about this. I'm a close personal friend of XEmacs, but I just can't endorse it anymore. I used to be a laissez-faire kinda guy, as long as you were using some flavor of Emacs. But at this point, if you're using XEmacs you're actively damaging not only your long-term productivity, but mine as well. So I'd like to ask you to think long and hard about switching. Soon.

If you're a local Emacs-Lisp guru, please offer your services to XEmacs users who would like to switch over. The more pain-free cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 migration is, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 faster it will happen.

If you're a graphic artist, consider making a nice, tasteful "Euthanize XEmacs!" logo. Not that message, precisely, but something along those lines. Make sure it's tasteful. Perhaps "XEmacs is dead – long live XEmacs"? Yes, I think that would do nicely.

If you happen to know someone on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XEmacs development team, send cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m some chocolates, or movie tickets, or something. A thank-you, even. We should honor cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir service. But those guys are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most qualified on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 planet to step in and start helping drive GNU Emacs forward, assuming cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FSF team will have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. Emacs is in very bad shape indeed if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y will not.

If you're a local system administrator, consider sudo rm -rf xemacs. Sorry, I mean consider politely asking your emacs-users mailing list if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y might be willing to set a timeline for deprecating XEmacs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby starting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most massive flamewar in your company's history. Can't hurt!

If you're seeing red, and you skipped most of this article so you could comment on how amazingly lame this idea is, I recommend taking a little walk and getting some fresh air first.

If you're RMS, thank you for making Emacs and all that ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r stuff, and for keeping it free. Please be nice to those who wish to help. You're scary to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point of unapproachability, just 'cuz you're you.

XEmacs team, JWZ, and XEmacs package authors: thank you all for helping drive progress in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 greatest piece of software of all time. I can only hope that someday I may have chops like that.

Now how about we turn this into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most famous reverse-fork in history?

Thursday, April 24, 2008

Settling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X focus-follows-mouse debate

I recently switched to using OS X full-time for all my client-side computing. Still using Linux on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 backends, of course, at home and at work, but I now use Macs for my client machines.

I'm not a Mac fanboy. I'm sort of a wannabe Mac fanboy, but I'm not familiar enough with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS yet (eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r as a user or as a programmer) to really rave about it. I will say this: it was kinda fun turning off that last Windows box for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last time.

My main reason for switching was that I'm getting old and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fonts look nicer. Pretty stupid reason, isn't it? I thought so too. But getting old kinda sneaks up on you. I've gone from preferring six-point font when I was twelve to 20-point font now that I'm 40. So at least for me, my ideal font point size appears to be (age/2).

That sucks.

One day I noticed that I could actually read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen when I was browsing in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple store, and I did some experimentation and found that yes, I can actually read normal-person's fonts on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac. And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y look kinda nice, too – cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 antialiasing engine seems to be smarter (and faster) than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ones I've seen on Windows and Linux.

So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re ya go. Fonts. And now I have to learn all this new stuff, like what all those weird little symbols mean on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keys, and how to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Finder, and what a "DMG file" is, and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r stuff. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen looks soooo nice, so it's worth it. How do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y do it? It's not just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fonts. OS X windows look whiter and cleaner than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir Windows/Linux cousins running on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same display with similar video hardware. It's a mystery to me, but it's kinda cool.

Almost pain-free migration

I've been using a work-issued MacBook Pro laptop for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past year, and that helped a lot with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transition, since when you're on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 road trying to get some work done, you have no choice but to figure out how to do basic OS tasks. So that was a nice, slow, reasonably pain-free way to teach myself cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 basic skills you need.

I only bring this up because I know a lot of programmers (myself included) who've tried Macs repeatedly and run away scared. If you stick with it a little longer, it's not too bad! Particularly with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir latest OS X release (Leopard), it's gotten a lot easier to do basic configuration for people accustomed to Linux.

For starters, it comes with a good X11 implementation, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a MacPorts project that ports all your favorite Unix stuff. And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're not lame half-broken ports like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ones you have to live with in Cygwin. For instance, in a Bash shell running inside Emacs you can ssh into a Linux box and not get a bunch of greebly control characters.

And OS X is Unix, based on FreeBSD, so all your normal favorite Unix stuff pretty much works cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same, or at least as much as you can expect across different flavors of Unix.

The only real reason I was using Windows at all, to be honest, was for hardware-device compatibility and for multimedia. The Mac has drivers for everything I cared about (my router, my printer, my camera, etc.) and beats Windows hands-down on any sort of multimedia, so it was becoming clear that Windows wasn't buying me much anymore.

I suppose I could do a blow-by-blow guide for how a Unix-and-Windows user can configure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir Mac for maximum happiness. If anyone's interested, anyway. Not today, though. The bottom line is that pretty much everything you don't like is configurable... with one ugly exception. And I don't mean "Mary Ann on Gilligan's Island Ugly", eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. I mean Ugly ugly.

The Big Focus Issue

Ever since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Dawn of Time (Jan 1, 1970), people have been bitching about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lack of focus-follows-mouse on Mac computers. They started complaining about it fourteen years before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first Mac was even released, that's how bad it was.

Every time cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y bring it up on Mac forums, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac users with non-Unix backgrounds ask "what's that?" And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n a bunch of wrong answers start flying around, with a few right answers interspersed but drowned out in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 noise.

So let me tell you what it is first, in case you're not from a Unix background. Focus-follows-mouse means that when you move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse cursor, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor gets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keyboard focus. But saying that confuses Mac people who all assume that "focused" is synonymous with "foreground", because that's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way it works on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac.

The confusion stems from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that focus-follows-mouse comes in not one, but two, yes that's right, two yummy flavors.

Flavor #1: autofocus — in this flavor, reminiscent perhaps of a sweet juicy mandarin orange, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse gets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keyboard focus but does not come to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 front. This allows you to interact with a partially-obscured window. It's especially useful when you have a terminal or shell window open, and it's running a background process that you want to observe... you guessed it, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 background! You leave a little bit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bottom and/or side of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window uncovered so you can keep an eye on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 output.

Real-life use case: let's say you're a programmer who writes in C++. You will, of course, spend most of your working day playing Solitaire and reading reddit, because C++ is too goddamned stupid to do anything but gigantic, slow batch compiles of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire dependency universe. So you have at least four windows open at any given time: your editor, your compile shell, your browser, and your Solitaire game. You've spent a lot of time adjusting your window configuration to be "just right", and unless you have a 30-inch screen (for instance, because you work for Google), your windows overlap.

Watching your compile status is like checking your rear-view mirror; you do it every 7 seconds or so, even though you know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 compiler will take a minimum of 15 minutes. It's like a slow-motion train wreck that you just can't tear your eyes from, even while playing Solitaire and reading reddit. And every once in a while you'll need to enter a command (e.g. "make", after you've fixed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 umpteenth compiler warning about doing a perfectly valid type conversion). The last thing you want is to have to click cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window to bring it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 front just so you can type "make", because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you'll need to go futz around with your window configuration again to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window to go to back to whatever Z-location it used to be in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window stack.

I know it doesn't sound like a big effort, but programmers are really, really lazy, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y like to minimize motion. They'd use feeder tubes if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Health Department would let cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.

So in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 autofocus flavor, it's important that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window that gets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focus does not automatically come to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 front.

Flavor #2: autoraise — in this pungent flavor, somewhat evocative of a slightly overripe Durian fruit left in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tropical sun for about nine hours, moving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse into a new window automatically brings that window to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 front. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 especially horrible default configuration, it comes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 front instantly, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 act of moving your mouse across cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen makes it look like that old "rectangles" screen saver, and your window configuration is utterly obliterated in under a second.

Many programmers feel that autofocus is delicate butterfly and autoraise is a big, stinky buffalo. That's just how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y feel about it. No accounting for taste. I, for one, think of autoraise as a big, stinky, deceased buffalo carcass that someone thoughtfully dragged into my living room while I was on vacation, probably towards cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vacation, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y turned up my cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmostat to 110°F, closed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 windows and tossed a Durian fruit at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wall for good measure.

But maybe it's just me.

So one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most annoying aspects of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole "how do I get focus-follows-mouse behavior on my Mac" debate is that everyone assumes you mean autoraise. There are a number of packages out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re, most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m commercial, that offer autoraise as a feature, and Mac users point you to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se products and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n get all smugly about how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y've solved your problem and how Macs still rule cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 universe, when in fact cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem is still festering away.

It's no wonder people still use Linux as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir UI. That one feature alone keeps hordes of programmers from switching. (And yes, you can get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behavior on Windows using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir TweakUI power tools, so some programmers use Windows as a Linux shell with a decent media player.)

Super-Stevey to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rescue (well, almost)

Given that I switched quite recently to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac, I'm still reeling from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lack of focus-follows-mouse behavior. To help you put yourself in my shoes, imagine that your latest operating system upgrade (whatever OS you happen to be running) includes a new mandatory feature wherein each time you click on a window to focus it, a loud alarm goes off ("BLONK! BLONK! BLONK! ...") and you have to open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 System menu and select "silence window alarm" to shut it up.

That's what not having autofocus is like to people who've been using it for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past 10 to 30 years (in my case, 20 years). BLONK! BLONK! BLONK! I'm serious. It's that bad. Not exaggerating even a tiny bit.

I'm sure you could eventually get used to this behavior, and even find yourself arguing on newsgroups that you racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 blonk blonk sound, since it reminds you that you've recently chosen to switch to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r application or to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r window within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current application, plus it's really not that big a deal because you can just open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 System menu and turn it off.

It's amazing how so many people choose to rationalize stuff cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're forced to live with. Why not just admit it sucks? Sometimes stuff sucks! C'mon, admit it! Jeez!

But even if you eventually managed to rationalize it, you'd be pretty fugging pissed off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first, oh, ten thousand or so times it happened to you after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 upgrade.

So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r day, after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 100th or so BLONK! BLONK! BLONK! alarm when I innocently tried to type into a different window, I found myself quietly contemplating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pros and cons of getting an assault rifle, heading down to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple campus, and making my opinions known to all until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SWAT team took me out. And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n I thought: "hey, as attractive as that option sounds right now, I have a better idea: why not fix it myself? I make occasional claims to being a programmer, right? How blonking hard can it be? I'll budget one evening for it."

I actually wound up spending 2 evenings on it, since although coming up to speed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple tools and APIs was almost trivial, this particular issue turned out to be thorny in a variety of unexpected ways.

But I did get it working, for some definition of "working", and now I'm in a position to settle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debate for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 forseeable future, which I estimate to be about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next five to seven years in this case.

The Definitive Answer

Short version: you can almost get it working, but not quite, on account of an arguable bug in one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Carbon (that is, Mac C++) APIs. What I got working was a system-wide autofocus mode that unfortunately only re-routes unmodified keys to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor. You can fake cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Shift modifier by translating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 key code manually, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Control, Command and Alt/Option keys never make it through to background applications. (They do get delivered to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 foreground app if your mouse is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug only happens for background apps.)

So if your use case is limited to, say, typing commands into a command shell, and you don't need to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 control, alt or command keys, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you can have working autofocus! In fact, you can even make it so that only your terminal windows (or any application list of your choice) get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 autofocus behavior, and all ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r applications get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 normal must-click-to-focus behavior. So even my "failed" attempt might yet hold some small utility for us ancient Unix hackers. I'll play with it for a while and see.

Long Version: As close as I came in my little 2-day effort, I now believe at this point that it's unlikely that autofocus will ever be available on Macs, sad as that news will be for thousands of would-be Mac users. And not just any users: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're programmers, all potentially capable of learning to write Mac applications and collectively enhancing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of Apple's platform. So it's kind of a big opportunity cost for Apple. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are both technical issues and design issues that make it a serious problem to support autofocus on Macs.

It's probably not impossible, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cost is high enough that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir OS engineers think about tackling it, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y'll probably decide it's not worth cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effort, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 company seems to fail to appreciate just how big a stumbling block cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lack of autofocus-sans-autoraise really is for so many competent Unix programmers out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re.

So, Apple OS engineers, I'm not saying you're not smart. I'm just saying you're not smart enough. ;-)

Just kidding, of course, and I'll dispense with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 child psychology. Here's why I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're not going to fix it. The rest of this blog entry consists of boring technical details, so if you're getting antsy, please feel completely free to skip to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very end.

How it works

First, one caveat: I'm not a Mac programmer. I don't even play one on TV. I just downloaded Xcode (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir development toolkit) for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first time three days ago. I've never written any Mac programs before this one, not even an AppleScript script, and I only started looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir APIs a couple days ago. So I might be wrong about some or all of this.

The first problem you encounter is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's no public Mac API for getting any sort of usable handle to a running application so you can interact with it programmatically. This is apparently for security reasons. I won't harp on this decision, although it does seem odd to deny sophisticated (read: sudo-enabled) users cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 choice of loading privileged apps into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir system. Any application can run amok with your filesystem, personal data and network connection, so it seems odd that you'd arbitrarily choose not to let cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m also run amok with your ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r running apps.

In any case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's a loophole. Apple, out of sheer generosity, goodwill, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kindness of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir heart o' hearts, and also partly because United States Federal Law requires it, but mostly out of sheer generosity, goodwill and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kindness of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir hearts, has provided a set of "Accessibility APIs" that give you a certain federally mandated level of remote control over running applications in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system.

OS X actually has two more or less discrete sets of APIs: one for C/C++ (Carbon), and one for Objective-C (Cocoa). Cocoa incidentally also happens to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API you use for Python and Ruby scripting on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac; I took a detour for a few hours and learned cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 basics of RubyCocoa, and was quite pleased at how well it worked.

One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reasons I took cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RubyCocoa detour was that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subset of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Accessibility APIs I needed for implementing autofocus is fairly cumbersome to explore using C++ and Xcode. I made an executive decision to spend (and potentially waste) some time seeing if I could make faster progress using one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scripting APIs, because I was encountering bugs and/or unexpected behavior that called for some exploratory programming.

Carbon offers an abstraction called an AXUIElementRef, which is a proxy object representing a UI element (e.g. an application, a window, or widget) in any running app on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system. This subsystem is designed and implemented entirely using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Properties Pattern, which, as it happens, I'll be blogging about at length in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very near future. Normally this pattern is quite flexible, and I can fully understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir reasons for using it here: it gave cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m legal compliance with an absolute minimum of effort.

But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Properties pattern is healthiest in a dynamic environment that lets you poke around reflectively to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 names of properties, fetch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir values, traverse parent links, and so on. Carbon provides APIs for manipulating all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se UI-element properties with C++, but it really is cumbersome: lots of casting, lots of wrappers, lots of recompilation every time you want to try just one more thing. Call me spoiled, but I only budgeted a day for this feature!

So I learned a bit of RubyCocoa, and it appears – as far as I can tell – that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relevant Accessibility APIs are only available through Carbon, and not through Cocoa, which means if you want to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, you can't use Objective-C, Ruby or Python. Or at least I couldn't find a way. If I'm wrong, someone please correct me, since I'd really like an experimentation platform that handles Carbon APIs that have no Cocoa equivalents.

Really Grubby Details

I told you it'd be boring! What are you still doing here?

OK, whatever. You're a glutton for punishment, I tell ya.

There are three basic components to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focus-follows-mouse solution:
  1. Create an "event tap" to filter all system keypresses.
  2. Find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frontmost window under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse
  3. Redirect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keypresses to that window.
That's all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is to it. This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 solution I envisioned before I'd even downloaded Xcode, and unsurprisingly, it appears to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only reasonable way to accomplish cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task in OS X. I mean, how else would you do it?

The event-tap API is straightforward, with just one teeny, minor exception almost not worth mentioning, which is that it doesn't work. It compiles, runs, and fails silently. This took me several hours to figure out. It turns out that event taps are considered to be part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Accessibility APIs, and for security reasons, your process eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r has to be running as root, or you have to enable "assistive technologies" in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Universal Access section of System Preferences. I stumbled across this in some random newsgroup after a LOT of searching. In retrospect it was kinda cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API documentation, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y didn't make it super clear.

Whew! There went several hours down cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 drain, but now I had a C program that fired up and listened for keypresses, printing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to stdout. The event-tap API gives you cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 option of swallowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keypresses (or changing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event, or even returning a new event to replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old one), so it's plenty flexible enough for our needs.

Next, I needed to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cursor, which first meant finding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global cursor position. This also turned out to be surprisingly non-obvious. The best solution I found, from someone's blog, was to create a NULL event and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n get its mouse coordinates. So intuitive! Just like Mom used to do it!

Sigh.

Once you have your mouse coordinates, you use a "hit test" to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window at that screen position. It's one of two Carbon-only APIs you need: you create a proxy for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system-wide UI object with AXUIElementCreateSystemWide, and pass it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global hit-test function AXUIElementCopyElementAtPosition to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UI element under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse.

Then it gets a little ugly, though not terribly so. These AXUIElementRef objects have all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir information in property lists. This would be trivial to navigate in RubyCocoa, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AXUI API set doesn't seem to exist in Cocoa — specifically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parts that deal with "any running application" racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than "your application".

So you grub around in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object and its parent chain, clunkily printing stuff in C++ and releasing reference-counts, until you find an ancestor with a "role" attribute of "application". That's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element you need for delivering keyboard events.

We can deliver cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 keyboard event to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unfocused window, through this poorly-documented API call:
AXError AXUIElementPostKeyboardEvent(AXUIElementRef application,
CGCharCode keyChar,
CGKeyCode virtualKey,
Boolean keyDown);

All good so far. Excluding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent figuring out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access-control problem with event taps, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent playing with RubyCocoa, I'm only about five hours into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole endeavor.

Oh yeah, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent dicking with Xcode trying to figure out how to add a library build target to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable. I've done it two or three times now and still can't remember how I did it.

The AXUIElementCopyElementAtPosition function points you to its non-Accessible cousin CGPostKeyboardEvent, which is also more or less undocumented. Can you tell cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y really don't want you to use this stuff? This cousin function has a teeny bit of explanation in its header file CGRemoteOperation.h, which Xcode provides no easy way of locating via search. You can look for it in Spotlight, hoping you'll get lucky and it won't hang like it did for me just now. Or you can do what I did and just use Google Desktop search to pop to it instantly.

The explanation in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header file says:
/*
* Syncá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365size keyboard events. Based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values entered,
* cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate key down, key up, and flags changed events are generated.
* If keyChar is NUL (0), an appropriate value will be guessed at, based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365
* default keymapping.
*
* All keystrokes needed to generate a character must be entered, including
* SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
* cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SHIFT key must be down, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 'z' key must go down, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SHIFT
* and 'z' key must be released:
* CGPostKeyboardEvent( (CGCharCode)0, (CGKeyCode)56, true ); // shift down
* CGPostKeyboardEvent( (CGCharCode)'Z', (CGKeyCode)6, true ); // 'z' down
* CGPostKeyboardEvent( (CGCharCode)'Z', (CGKeyCode)6, false ); // 'z' up
* CGPostKeyboardEvent( (CGCharCode)0, (CGKeyCode)56, false ); // 'shift up
*/

That's it. That's what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y give you. Open questions about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 explanation include (a) why are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y passing capital-'Z' if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y already reported that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shift key was down, (b) if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's a guesser when you pass NULL, why do you need to pass 'Z', (c) how do you get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 char code for a given key code, and is it cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same on all keyboards, and (d) why didn't cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y include a "THE FIRST PARAGRAH IS A LIE" disclaimer around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first paragraph?

Open questions be damned. We fearlessly press on, and just pass "whatever" and see what happens. Specifically, I always pass NULL for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 char code, and pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 key code I got from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event tap callback as-is.

And it worked! Sort of! I start my little app (which has no UI), move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse into a window from a non-foreground application, and I can type into it!

Except I can only type unmodified keys. It's completely ignoring my keyboard event posts for Shift, Control, Alt and Command. That's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lie part. They said cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y'd generate flags changed events. They lied.

After some more painful C++ experimentation, I find that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call does NOT ignore modifier keys when posting to (a) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focused application or (b) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system-wide application, which just posts to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focused app. The call only drops modifier keys on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 floor for non-focused apps.

There's a big ol' thread about this exact problem from six years ago on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple accessibility-dev mailing list. Six years! I read every last word of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread.

The first takeaway is that Apple OS engineers don't want you to do stuff that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't want you to do, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y specifically define "stuff cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't want you to do" as "stuff cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't think you want to do." This is actually endemic to Apple forums in general. Whenever someone says "I want focus follows mouse behavior!", some people inevitably reply that "you really don't want to do this". It's that whole "we designed it cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right way for everyone" mentality that turns off so many would-be Mac users.

For what it's worth, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple engineers really were trying to be helpful in this guy's situation, and I know how hard it can be to respond to a mailing list in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 capacity of "developer representing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 company". But it took cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m a long time to understand his needs, because (and I'm speculating here) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y implemented cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Accessibility APIs only because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir Mom told cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't truly appreciate at a deep level what it means to have a disability, and how important it is for many people to be able to choose a different UI paradigm.

And yes, I am taking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arguably un-PC position that having your fingers hardwired to focus-follows-mouse from 20 years of use can be viewed as a minor disability of sorts. I'll be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first to admit that it's not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kind of "real" disability cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 government probably had in mind when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y mandated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Accessibility APIs.

But I did switch to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac because my eyes are slowly beginning to fail. Ironic that I should be forced to trade one disability for anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r.

The underlying issue

OK, let's assume for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 moment that Apple really does have our best interests at heart, and that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can get over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 painful notion that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir usability test findings may not actually apply to 100% of all users 100% of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time.

Even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y wanted to help fix it — and in this case, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y'd need to do is NOT drop cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modifier keys on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 floor when you call AXUIElementPostKeyboardEvent — cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are some deep-rooted architectural issues at play here, and I finally "got it" while reading that thread.

The problem is that Macs, always and forever, have put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 menu bar of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focused application at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screen. The menu bars of unfocused applications are hidden and are not in any way user-interactible.

As you might expect, this UI assumption has been baked into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac APIs from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very beginning. Programmers will take advantage of any axiom cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can in order to get things working, so over time this has turned from a UI design assumption into an architectural "feature".

In particular, when an app is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 background, its menu structure may not be intact, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app may be in a state that assumes it will not be receiving any keyboard input. One concrete example mentioned in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread was that when an app is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 background, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 child menu items do not have parent links (although cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parents still have pointers to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 children.)

This has serious ramifications for focus-follows-mouse. There are certain built-in hotkeys that can activate menu entries, and apps are also free to define cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own. If you try to activate a menu in a background application, it could in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory wind up crashing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app is assuming an intact menu structure and is traversing bottom-up racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than top-down.

You could attempt a knee-jerk solution by allowing Control and Alt through, but deny cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Command modifier, since that's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most common menu-activation modifier (I think). But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r class of applications (Emacs included) that dynamically generates at least part of its menu structure based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data content. For instance, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emacs Imenu package generates a list of jump targets from a source-code buffer. Even typing a new function definition could still trigger a rebuild of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IMenu, which (for all anyone knows) could crash Emacs.

You could of course ask app developers to fix this on an application-by-application basis, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are generations of legacy apps that can never be fixed. The only way to guarantee that pressing a key could never crash an application would be to fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X user-interface architecture to normalize application behavior for foreground and background operation. This could be hard. It could expose its own set of difficult or even intractable problems for legacy apps. Or maybe it's really easy. I don't know, since I can't see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir code. But I suspect it's not easy.

And Apple has no real motivation to fix it, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir UI was designed for "everyone". People who would use focus-follows-mouse are presumably a tiny minority, so even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're mostly programmers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cost/benefit likely isn't cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re.

It is, of course, completely fixable if Apple really wanted to fix it. I've heard many war stories over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 years from Microsoft folks who've had to put compatibility hacks into OS releases, some quite extensive, in order to support popular applications that relied on undocumented OS behavior that suddenly broke. Imagine those poor guys that had to implement perfect DOS/Windows emulation on NT, for example. I suspect that by comparison, fixing focus-follows-mouse would be relatively straightforward.

But I predict it won't happen in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next 5 to 7 years, unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 government suddenly decides that this API is required for properly assistive technologies.

It's interesting that you can get so close using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing APIs: I have true focus-follows-mouse behavior implemented for non-modified keys. Sure, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 window doesn't actually focus, so some applications don't even show a cursor. But if you're willing to live with occasional glitches, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 feature works great.

In any event, what's weirdest about all this is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API lets you send non-modifier keys to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 background app, because as I pointed out, it's still possible for vanilla keys to crash applications! If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 state of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app is materially different when it's unfocused, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app isn't expecting keyboard input when unfocused, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it could crash. Dropping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modifier keys on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 floor may reduce cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 probability of Badness, but it certainly doesn't eliminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 possibility.

Was it an accident that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y let any keys through at all? That would surprise me greatly, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS engineers seem determined to close undocumented behavior loopholes. But if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y had a reason (perhaps a legal reason) to permit unmodified keys through, what was it about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reason that lets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m drop cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modifier keys?

I wish I knew.

Open letter to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple Wish Fairy

If I could wave a magic wand, I'd ask for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API to pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modifier keys along to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app, and just put a note in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 docs that Bad Things could happen, so Buyer Beware.

They already do this for those exact APIs anyway. CGPostKeyboardEvent's documentation says: "This function is not recommended for general use because of undocumented special cases and undesirable side effects." And this is for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API that only talks to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 focused foreground app! The AXUI version is obviously double-buyer-beware, and apps can't even use it without prompting for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 superuser password, unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user has purposely enabled assistive technologies.

There would be bugs, yes. Some applications would have to push out new releases to properly support focus-follows-mouse, and some legacy apps would never be fixed. But you could disable cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behavior on an app-by-app basis, or just take a "Doctor, it hurts when I do this" approach.

Unfortunately I don't have a magic wand; all I have is my distinctly nonmagical blog, which I'm using to soocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 myself via copious whining.

Epilogue

This whole thing has been an interesting lesson in how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 government can actually force companies to open up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir locked-down systems. The whole "you'll have it our way, and like it" mentality is crumbling with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se assistive technologies. I hope cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 feds mandate opening things up even furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, since we're only partway cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re so far.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interim, I'm sure I'll eventually get used to life without autofocus. BLONK! My 30-inch screen helps, as does Spaces, since it's easier to give windows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own non-overlapping real estate.

I might even give autoraise anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r try. Some developers have implemented it in a horrible way, by generating a mouse click when you move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse into a window, which often results in activating UI objects unintentionally just by moving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mouse. Ouch. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re might be some commercial implementations that do it "right", or I can just hack my autofocus app to do it that way. Combined with an autoraise delay and minimizing my overlapping windows, it might just work. We'll see.

And everything else so far about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac has seemed pretty nice, or when it's been not nice, at least it's been fixable with a little configuration effort. I liked cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS X APIs on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RubyCocoa thing is pretty sweet. I might even wind up writing some native clients — something I thought I'd never do again, given how awful my Windows native-client experiences have been over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 years.

So I'll keep using my Macs. They're all just plumbing for Emacs, anyway. And now my plumbing has nicer fonts.

If you skipped straight to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end...

...you didn't miss much. See you next time!