I'm currently working on porting Emacs to Maemo, and specifically
getting the Emacs frames to bring up the pop-up keyboard. Thanks to
help from people on #maemo, especially Aaron Levinson, I'm getting
somewhere. I can now see the keyboard if I lose focus (click on a
menu outside Emacs), and once the keyboard is up, keystrokes make it
in. The keyboard doesn't come back if I click in the frame, though.
I'm using the latest Emacs from CVS for this. The patch is against
CVS: emacs/src/xterm.c
I asked on the Emacs developer list how to get the GDK window for an
Emacs frame. I don't think that's possible (they may not use GDK at
all and go straight to X), so I may have to keep using a temporary
foreign GDK window (see my code, it's done on FocusIn when focus
changes, but I also asked the Emacs developers where's the right place
to do that).
Note that Emacs frames are not X windows or GTK windows, necessarily.
There's lots of crufty code in Emacs to accomodate text-only startup,
and it makes this project a challenge.
My questions:
1) does anyone have suggestions on this? I'm far from experienced
with X and GTK, and would appreciate any help at all. I'd be happier
concentrating on Emacs packaging, writing site-init scripts, etc. If
the Hildon experts could look at it, I'd be very relieved.
2) how do I add Control and Meta to the pop-up keyboard? Meta can be
simulated with the ESC key, but Control is a must-have. I'd hate to
steal screen real estate as the latest osso-xterm does, just to
provide the Control key (there's no point in Emacs in providing all
the other Control combinations, since almost all are used).
3) how do I add the symbols to the key event loop? Right now, only
ASCII (7bit) makes it through, I think.
Thanks
Ted
p.s. the .deb is 78 MB right now, but I haven't pruned it because I'm
trying to get the keyboard working. I hope it will be much less in
the final release.
? xterm.patch
Index: xterm.c
===================================================================
RCS file: /sources/emacs/emacs/src/xterm.c,v
retrieving revision 1.936
diff -u -r1.936 xterm.c
--- xterm.c 10 Dec 2006 23:32:00 -0000 1.936
+++ xterm.c 24 Jan 2007 18:53:59 -0000
@@ -164,6 +164,13 @@
int use_xim = 0; /* configure --without-xim */
#endif
+#include <hildon-widgets/hildon-program.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtk.h>
+
+GtkIMContext *im_context; /* the context for the keyboard input method */
+Atom hildon_com, hildon_utf, hildon_cls;
+
/* Non-nil means Emacs uses toolkit scroll bars. */
@@ -3177,7 +3184,7 @@
struct frame *frame;
{
struct frame *old_focus = dpyinfo->x_focus_frame;
-
+
if (frame != dpyinfo->x_focus_frame)
{
/* Set this before calling other routines, so that they see
@@ -3216,6 +3223,7 @@
struct frame *frame;
struct input_event *bufp;
{
+ GdkWindow *gdkWindow;
if (type == FocusIn)
{
if (dpyinfo->x_focus_event_frame != frame)
@@ -3240,6 +3248,11 @@
if (FRAME_XIC (frame))
XSetICFocus (FRAME_XIC (frame));
#endif
+ im_context = gtk_im_multicontext_new();
+ gdkWindow = gdk_window_foreign_new(FRAME_X_WINDOW(frame));
+ gtk_im_context_set_client_window(im_context, gdkWindow); /* we need the frame's GDK window */
+ hildon_gtk_im_context_show(im_context);
+ xassert (im_content != NULL);
}
else if (type == FocusOut)
{
@@ -3255,6 +3268,9 @@
if (FRAME_XIC (frame))
XUnsetICFocus (FRAME_XIC (frame));
#endif
+ hildon_gtk_im_context_hide(im_context);
+ gtk_im_context_reset(im_context);
+ g_object_unref(im_context);
}
}
@@ -5691,25 +5707,91 @@
inev.ie.kind = NO_EVENT;
inev.ie.arg = Qnil;
+ hildon_com = XInternAtom(dpyinfo->display, "_HILDON_IM_COM", TRUE);
+ hildon_utf = XInternAtom(dpyinfo->display, "_HILDON_IM_INSERT_UTF8", TRUE);
+ hildon_cls = XInternAtom(dpyinfo->display, "_HILDON_IM_CLOSE", TRUE);
+
switch (event.type)
{
case ClientMessage:
{
- if (event.xclient.message_type
- == dpyinfo->Xatom_wm_protocols
- && event.xclient.format == 32)
- {
- if (event.xclient.data.l[0]
- == dpyinfo->Xatom_wm_take_focus)
- {
- /* Use x_any_window_to_frame because this
- could be the shell widget window
- if the frame has no title bar. */
- f = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ if (event.xclient.message_type == hildon_cls) /* keyboard closed */
+ {
+ printf ("Got hildon_cls event\n");
+ if (NULL != im_context)
+ {
+ hildon_gtk_im_context_hide(im_context);
+ gtk_im_context_reset(im_context);
+ g_object_unref(im_context);
+ im_context = NULL;
+ }
+ }
+ else if (event.xclient.message_type == hildon_utf) /* keyboard input */
+ {
+ printf ("Got hildon_utf event\n");
+ XEvent kev = event; /* create new event */
+ KeySym sym = XStringToKeysym(&event.xclient.data.b[4]); /* read the key */
+
+ if (!sym) sym = event.xclient.data.b[4]; /* fall back to input */
+
+ kev.type = KeyPress; /* keyboard event */
+ kev.xkey.root = event.xclient.window;
+ kev.xkey.subwindow = None;
+ kev.xkey.time = CurrentTime;
+ kev.xkey.x = kev.xkey.y = kev.xkey.x_root = kev.xkey.y_root = 1;
+ kev.xkey.same_screen = TRUE;
+ kev.xkey.keycode = XKeysymToKeycode(dpyinfo->display, sym); /* convert to key code */
+
+ if (isupper(event.xclient.data.b[4])) /* upper case letter? */
+ kev.xkey.state = ShiftMask; /* yes: we need shift */
+ else
+ kev.xkey.state = 0;
+
+ XSendEvent(dpyinfo->display, event.xclient.window, TRUE, KeyPressMask, &kev);
+
+ kev.type = KeyRelease; /* key release event */
+ XSendEvent(dpyinfo->display, event.xclient.window, TRUE, KeyReleaseMask, &kev);
+ }
+ else if (event.xclient.message_type == hildon_com)/* special key/event */
+ {
+ printf ("Got hildon_com event\n");
+ switch (event.xclient.data.b[4])
+ {
+ case 0: /* return / enter */
+ /* send XK_Return (or handle specially) */
+ break;
+ case 1: /* tab */
+ /* send XK_Tab (or handle specially) */
+ break;
+ case 2: /* backspace */
+ /* send XK_BackSpace (or handle specially) */
+ break;
+ case 4: /* state change */
+ break;
+ case 7: /* special char */
+ break;
+ default:
+ printf("Unknown IM event data %d\n",
+ (int) event.xclient.data.b[4]);
+ }
+ }
+ else
+ {
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_protocols
+ && event.xclient.format == 32)
+ {
+ if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_take_focus)
+ {
+ /* Use x_any_window_to_frame because this
+ could be the shell widget window
+ if the frame has no title bar. */
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
#ifdef HAVE_X_I18N
- /* Not quite sure this is needed -pd */
- if (f && FRAME_XIC (f))
- XSetICFocus (FRAME_XIC (f));
+ /* Not quite sure this is needed -pd */
+ if (f && FRAME_XIC (f))
+ XSetICFocus (FRAME_XIC (f));
#endif
#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
instructs the WM to set the input focus automatically for
@@ -5724,147 +5806,148 @@
below can generate additional FocusIn events which confuse
Emacs. */
- /* Since we set WM_TAKE_FOCUS, we must call
- XSetInputFocus explicitly. But not if f is null,
- since that might be an event for a deleted frame. */
- if (f)
- {
- Display *d = event.xclient.display;
- /* Catch and ignore errors, in case window has been
- iconified by a window manager such as GWM. */
- x_catch_errors (d);
- XSetInputFocus (d, event.xclient.window,
- /* The ICCCM says this is
- the only valid choice. */
- RevertToParent,
- event.xclient.data.l[1]);
- /* This is needed to detect the error
- if there is an error. */
- XSync (d, False);
- x_uncatch_errors ();
- }
- /* Not certain about handling scroll bars here */
+ /* Since we set WM_TAKE_FOCUS, we must call
+ XSetInputFocus explicitly. But not if f is null,
+ since that might be an event for a deleted frame. */
+ if (f)
+ {
+ Display *d = event.xclient.display;
+ /* Catch and ignore errors, in case window has been
+ iconified by a window manager such as GWM. */
+ x_catch_errors (d);
+ XSetInputFocus (d, event.xclient.window,
+ /* The ICCCM says this is
+ the only valid choice. */
+ RevertToParent,
+ event.xclient.data.l[1]);
+ /* This is needed to detect the error
+ if there is an error. */
+ XSync (d, False);
+ x_uncatch_errors ();
+ }
+ /* Not certain about handling scroll bars here */
#endif /* 0 */
- goto done;
- }
+ goto done;
+ }
- if (event.xclient.data.l[0]
- == dpyinfo->Xatom_wm_save_yourself)
- {
- /* Save state modify the WM_COMMAND property to
- something which can reinstate us. This notifies
- the session manager, who's looking for such a
- PropertyNotify. Can restart processing when
- a keyboard or mouse event arrives. */
- /* If we have a session manager, don't set this.
- KDE will then start two Emacsen, one for the
- session manager and one for this. */
+ if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_save_yourself)
+ {
+ /* Save state modify the WM_COMMAND property to
+ something which can reinstate us. This notifies
+ the session manager, who's looking for such a
+ PropertyNotify. Can restart processing when
+ a keyboard or mouse event arrives. */
+ /* If we have a session manager, don't set this.
+ KDE will then start two Emacsen, one for the
+ session manager and one for this. */
#ifdef HAVE_X_SM
- if (! x_session_have_connection ())
+ if (! x_session_have_connection ())
#endif
- {
- f = x_top_window_to_frame (dpyinfo,
- event.xclient.window);
- /* This is just so we only give real data once
- for a single Emacs process. */
- if (f == SELECTED_FRAME ())
- XSetCommand (FRAME_X_DISPLAY (f),
- event.xclient.window,
- initial_argv, initial_argc);
- else if (f)
- XSetCommand (FRAME_X_DISPLAY (f),
- event.xclient.window,
- 0, 0);
- }
- goto done;
- }
+ {
+ f = x_top_window_to_frame (dpyinfo,
+ event.xclient.window);
+ /* This is just so we only give real data once
+ for a single Emacs process. */
+ if (f == SELECTED_FRAME ())
+ XSetCommand (FRAME_X_DISPLAY (f),
+ event.xclient.window,
+ initial_argv, initial_argc);
+ else if (f)
+ XSetCommand (FRAME_X_DISPLAY (f),
+ event.xclient.window,
+ 0, 0);
+ }
+ goto done;
+ }
- if (event.xclient.data.l[0]
- == dpyinfo->Xatom_wm_delete_window)
- {
- f = x_any_window_to_frame (dpyinfo,
- event.xclient.window);
- if (!f)
- goto OTHER; /* May be a dialog that is to be removed */
+ if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_delete_window)
+ {
+ f = x_any_window_to_frame (dpyinfo,
+ event.xclient.window);
+ if (!f)
+ goto OTHER; /* May be a dialog that is to be removed */
+
+ inev.ie.kind = DELETE_WINDOW_EVENT;
+ XSETFRAME (inev.ie.frame_or_window, f);
+ goto done;
+ }
- inev.ie.kind = DELETE_WINDOW_EVENT;
- XSETFRAME (inev.ie.frame_or_window, f);
goto done;
- }
-
- goto done;
- }
+ }
- if (event.xclient.message_type
- == dpyinfo->Xatom_wm_configure_denied)
- {
- goto done;
- }
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_configure_denied)
+ {
+ goto done;
+ }
- if (event.xclient.message_type
- == dpyinfo->Xatom_wm_window_moved)
- {
- int new_x, new_y;
- f = x_window_to_frame (dpyinfo, event.xclient.window);
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_window_moved)
+ {
+ int new_x, new_y;
+ f = x_window_to_frame (dpyinfo, event.xclient.window);
- new_x = event.xclient.data.s[0];
- new_y = event.xclient.data.s[1];
+ new_x = event.xclient.data.s[0];
+ new_y = event.xclient.data.s[1];
- if (f)
- {
- f->left_pos = new_x;
- f->top_pos = new_y;
- }
- goto done;
- }
+ if (f)
+ {
+ f->left_pos = new_x;
+ f->top_pos = new_y;
+ }
+ goto done;
+ }
#ifdef HACK_EDITRES
- if (event.xclient.message_type
- == dpyinfo->Xatom_editres)
- {
- f = x_any_window_to_frame (dpyinfo, event.xclient.window);
- if (f)
- _XEditResCheckMessages (f->output_data.x->widget, NULL,
- &event, NULL);
- goto done;
- }
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_editres)
+ {
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ if (f)
+ _XEditResCheckMessages (f->output_data.x->widget, NULL,
+ &event, NULL);
+ goto done;
+ }
#endif /* HACK_EDITRES */
- if ((event.xclient.message_type
- == dpyinfo->Xatom_DONE)
- || (event.xclient.message_type
- == dpyinfo->Xatom_PAGE))
- {
- /* Ghostview job completed. Kill it. We could
- reply with "Next" if we received "Page", but we
- currently never do because we are interested in
- images, only, which should have 1 page. */
- Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
- f = x_window_to_frame (dpyinfo, event.xclient.window);
- if (!f)
- goto OTHER;
- x_kill_gs_process (pixmap, f);
- expose_frame (f, 0, 0, 0, 0);
- goto done;
- }
+ if ((event.xclient.message_type
+ == dpyinfo->Xatom_DONE)
+ || (event.xclient.message_type
+ == dpyinfo->Xatom_PAGE))
+ {
+ /* Ghostview job completed. Kill it. We could
+ reply with "Next" if we received "Page", but we
+ currently never do because we are interested in
+ images, only, which should have 1 page. */
+ Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
+ f = x_window_to_frame (dpyinfo, event.xclient.window);
+ if (!f)
+ goto OTHER;
+ x_kill_gs_process (pixmap, f);
+ expose_frame (f, 0, 0, 0, 0);
+ goto done;
+ }
#ifdef USE_TOOLKIT_SCROLL_BARS
- /* Scroll bar callbacks send a ClientMessage from which
- we construct an input_event. */
- if (event.xclient.message_type
- == dpyinfo->Xatom_Scrollbar)
- {
- x_scroll_bar_to_input_event (&event, &inev.ie);
- *finish = X_EVENT_GOTO_OUT;
- goto done;
- }
+ /* Scroll bar callbacks send a ClientMessage from which
+ we construct an input_event. */
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_Scrollbar)
+ {
+ x_scroll_bar_to_input_event (&event, &inev.ie);
+ *finish = X_EVENT_GOTO_OUT;
+ goto done;
+ }
#endif /* USE_TOOLKIT_SCROLL_BARS */
- f = x_any_window_to_frame (dpyinfo, event.xclient.window);
- if (!f)
- goto OTHER;
- if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev.ie))
- *finish = X_EVENT_DROP;
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ if (!f)
+ goto OTHER;
+ if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev.ie))
+ *finish = X_EVENT_DROP;
+ }
}
break;
@@ -10434,8 +10517,11 @@
XSetLocaleModifiers ("");
#endif
+ HildonProgram *program;
gtk_init (&argc, &argv2);
+ program = HILDON_PROGRAM(hildon_program_get_instance());
+
/* gtk_init does set_locale. We must fix locale after calling it. */
fixup_locale ();
xg_initialize ();
_______________________________________________
maemo-developers mailing list
[email protected]
https://maemo.org/mailman/listinfo/maemo-developers