Complete the keybindings stuff and use it for the home page

This commit is contained in:
Marco Pesenti Gritti 2006-08-25 14:03:48 +02:00
parent 4425e14f13
commit 6e920265ad
7 changed files with 146 additions and 85 deletions

View File

@ -1,4 +1,5 @@
INCLUDES = \ INCLUDES = \
$(WARN_CFLAGS) \
$(PYTHON_INCLUDES) \ $(PYTHON_INCLUDES) \
$(PYGTK_CFLAGS) \ $(PYGTK_CFLAGS) \
$(GLOBALKEYS_CFLAGS) $(GLOBALKEYS_CFLAGS)

View File

@ -19,45 +19,111 @@
#include <X11/X.h> #include <X11/X.h>
#include <gdk/gdkscreen.h> #include <gdk/gdkscreen.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#include <gdk/gdk.h>
#include "sugar-key-grabber.h" #include "sugar-key-grabber.h"
#include "eggaccelerators.h"
/* we exclude shift, GDK_CONTROL_MASK and GDK_MOD1_MASK since we know what /* we exclude shift, GDK_CONTROL_MASK and GDK_MOD1_MASK since we know what
these modifiers mean these modifiers mean
these are the mods whose combinations are bound by the keygrabbing code */ these are the mods whose combinations are bound by the keygrabbing code */
#define IGNORED_MODS (0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | \ #define IGNORED_MODS (0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | \
GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK) GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK)
/* these are the ones we actually use for global keys, we always only check
* for these set */
#define USED_MODS (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)
struct _SugarKeyGrabber { struct _SugarKeyGrabber {
GObject base_instance; GObject base_instance;
GdkWindow *root; GdkWindow *root;
GList *keys;
}; };
struct _SugarKeyGrabberClass { struct _SugarKeyGrabberClass {
GObjectClass base_class; GObjectClass base_class;
void (* key_pressed) (SugarKeyGrabber *grabber,
const char *key);
}; };
enum {
KEY_PRESSED,
N_SIGNALS
};
typedef struct {
char *key;
guint keysym;
guint state;
guint keycode;
} Key;
G_DEFINE_TYPE(SugarKeyGrabber, sugar_key_grabber, G_TYPE_OBJECT) G_DEFINE_TYPE(SugarKeyGrabber, sugar_key_grabber, G_TYPE_OBJECT)
static guint signals[N_SIGNALS];
static void static void
sugar_key_grabber_class_init(SugarKeyGrabberClass *key_grabber_class) free_key_info(Key *key_info)
{ {
g_free(key_info->key);
g_free(key_info);
}
static void
sugar_key_grabber_dispose (GObject *object)
{
SugarKeyGrabber *grabber = SUGAR_KEY_GRABBER(object);
if (grabber->keys) {
g_list_foreach(grabber->keys, (GFunc)free_key_info, NULL);
g_list_free(grabber->keys);
grabber->keys = NULL;
}
}
static void
sugar_key_grabber_class_init(SugarKeyGrabberClass *grabber_class)
{
GObjectClass *g_object_class = G_OBJECT_CLASS (grabber_class);
g_object_class->dispose = sugar_key_grabber_dispose;
signals[KEY_PRESSED] = g_signal_new ("key-pressed",
G_TYPE_FROM_CLASS (grabber_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (SugarKeyGrabberClass, key_pressed),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
} }
static GdkFilterReturn static GdkFilterReturn
filter_events(GdkXEvent *xevent, GdkEvent *event, gpointer data) filter_events(GdkXEvent *xevent, GdkEvent *event, gpointer data)
{ {
SugarKeyGrabber *grabber = (SugarKeyGrabber *)data; SugarKeyGrabber *grabber = (SugarKeyGrabber *)data;
XEvent *xev = (XEvent *)xevent; XEvent *xev = (XEvent *)xevent;
XAnyEvent *xanyev = (XAnyEvent *)xevent;
guint keycode, state;
int i;
keycode = xev->xkey.keycode; if (xev->type == KeyPress) {
state = xev->xkey.state; GList *l;
guint keycode, state;
g_print("KeyCode %d", keycode); keycode = xev->xkey.keycode;
state = xev->xkey.state;
for (l = grabber->keys; l != NULL; l = l->next) {
Key *keyinfo = (Key *)l->data;
if (keyinfo->keycode == keycode &&
(state & USED_MODS) == keyinfo->state) {
g_signal_emit (grabber, signals[KEY_PRESSED],
0, keyinfo->key);
return GDK_FILTER_REMOVE;
}
}
}
return GDK_FILTER_CONTINUE;
} }
static void static void
@ -67,60 +133,74 @@ sugar_key_grabber_init(SugarKeyGrabber *grabber)
screen = gdk_screen_get_default(); screen = gdk_screen_get_default();
grabber->root = gdk_screen_get_root_window(screen); grabber->root = gdk_screen_get_root_window(screen);
grabber->keys = NULL;
gdk_window_add_filter(grabber->root, filter_events, grabber); gdk_window_add_filter(grabber->root, filter_events, grabber);
} }
/* grab_key and grab_key_real are from
* gnome-control-center/gnome-settings-daemon/gnome-settings-multimedia-keys.c
*/
/* inspired from all_combinations from gnome-panel/gnome-panel/global-keys.c */ static gboolean
#define N_BITS 32 grab_key_real (Key *key, GdkWindow *root, gboolean grab, int result)
static int
get_modifier(guint state)
{ {
int indexes[N_BITS];/*indexes of bits we need to flip*/ gdk_error_trap_push ();
int i, bit, bits_set_cnt; if (grab)
int uppervalue; XGrabKey (GDK_DISPLAY(), key->keycode, (result | key->state),
int result = 0; GDK_WINDOW_XID (root), True, GrabModeAsync, GrabModeAsync);
guint mask_to_traverse = IGNORED_MODS & ~ state; else
XUngrabKey(GDK_DISPLAY(), key->keycode, (result | key->state),
GDK_WINDOW_XID (root));
gdk_flush ();
bit = 0; gdk_error_trap_pop ();
for (i = 0; i < N_BITS; i++) {
if (mask_to_traverse & (1<<i))
indexes[bit++]=i;
}
bits_set_cnt = bit; return TRUE;
}
uppervalue = 1<<bits_set_cnt; #define N_BITS 32
for (i = 0; i < uppervalue; i++) { static void
int j; grab_key (SugarKeyGrabber *grabber, Key *key, gboolean grab)
{
int indexes[N_BITS];/*indexes of bits we need to flip*/
int i, bit, bits_set_cnt;
int uppervalue;
guint mask_to_traverse = IGNORED_MODS & ~ key->state;
for (j = 0; j < bits_set_cnt; j++) { bit = 0;
if (i & (1<<j)) for (i = 0; i < N_BITS; i++) {
result |= (1<<indexes[j]); if (mask_to_traverse & (1<<i))
} indexes[bit++]=i;
}
} bits_set_cnt = bit;
return (result | state); uppervalue = 1<<bits_set_cnt;
for (i = 0; i < uppervalue; i++) {
int j, result = 0;
for (j = 0; j < bits_set_cnt; j++) {
if (i & (1<<j))
result |= (1<<indexes[j]);
}
if (grab_key_real (key, grabber->root, grab, result) == FALSE)
return;
}
} }
void void
sugar_key_grabber_grab(SugarKeyGrabber *grabber, const char *key) sugar_key_grabber_grab(SugarKeyGrabber *grabber, const char *key)
{ {
guint keysym; Key *keyinfo;
guint state;
guint keycode;
gdk_error_trap_push (); keyinfo = g_new0 (Key, 1);
keyinfo->key = g_strdup(key);
egg_accelerator_parse_virtual (key, &keyinfo->keysym,
&keyinfo->keycode, &keyinfo->state);
egg_accelerator_parse_virtual (key, &keysym, &keycode, &state); grab_key(grabber, keyinfo, TRUE);
XGrabKey (GDK_DISPLAY(), keycode, get_modifier(state), grabber->keys = g_list_append(grabber->keys, keyinfo);
GDK_WINDOW_XID (grabber->root), True,
GrabModeAsync, GrabModeAsync);
gdk_flush ();
gdk_error_trap_pop ();
} }

View File

@ -3,6 +3,7 @@ AC_INIT([Sugar],[0.22],[],[sugar])
AC_PREREQ([2.59]) AC_PREREQ([2.59])
GNOME_COMMON_INIT GNOME_COMMON_INIT
GNOME_COMPILE_WARNINGS
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])

View File

@ -6,7 +6,6 @@ bin_SCRIPTS = \
sugar-activity-factory \ sugar-activity-factory \
sugar-console \ sugar-console \
sugar-people \ sugar-people \
sugar-zoom \
sugar-presence-service sugar-presence-service
sugardir = $(pkgdatadir)/shell sugardir = $(pkgdatadir)/shell

View File

@ -41,14 +41,6 @@ class ShellDbusService(dbus.service.Object):
def show_console(self): def show_console(self):
gobject.idle_add(self.__show_console_idle) gobject.idle_add(self.__show_console_idle)
@dbus.service.method('com.redhat.Sugar.Shell')
def zoom_in(self):
self._shell.zoom_in()
@dbus.service.method('com.redhat.Sugar.Shell')
def zoom_out(self):
self._shell.zoom_out()
class Shell(gobject.GObject): class Shell(gobject.GObject):
ZOOM_MESH = 0 ZOOM_MESH = 0
ZOOM_FRIENDS = 1 ZOOM_FRIENDS = 1
@ -66,7 +58,11 @@ class Shell(gobject.GObject):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
key_grabber = KeyGrabber() key_grabber = KeyGrabber()
key_grabber.grab('F8') key_grabber.connect('key-pressed', self.__global_key_pressed_cb)
key_grabber.grab('F1')
key_grabber.grab('F2')
key_grabber.grab('F3')
key_grabber.grab('F4')
self._screen = wnck.screen_get_default() self._screen = wnck.screen_get_default()
self._hosts = {} self._hosts = {}
@ -87,6 +83,16 @@ class Shell(gobject.GObject):
else: else:
self.start() self.start()
def __global_key_pressed_cb(self, grabber, key):
if key == 'F1':
self.set_zoom_level(Shell.ZOOM_ACTIVITY)
elif key == 'F2':
self.set_zoom_level(Shell.ZOOM_HOME)
elif key == 'F3':
self.set_zoom_level(Shell.ZOOM_FRIENDS)
elif key == 'F4':
self.set_zoom_level(Shell.ZOOM_MESH)
def __first_time_dialog_destroy_cb(self, dialog): def __first_time_dialog_destroy_cb(self, dialog):
self.start() self.start()
@ -105,7 +111,7 @@ class Shell(gobject.GObject):
home_model = HomeModel() home_model = HomeModel()
self._home_window.set_model(home_model) self._home_window.set_model(home_model)
self._set_zoom_level(Shell.ZOOM_HOME) self.set_zoom_level(Shell.ZOOM_HOME)
self._panel_manager = PanelManager(self) self._panel_manager = PanelManager(self)
@ -204,7 +210,7 @@ class Shell(gobject.GObject):
def get_chat_controller(self): def get_chat_controller(self):
return self._chat_controller return self._chat_controller
def _set_zoom_level(self, level): def set_zoom_level(self, level):
self._zoom_level = level self._zoom_level = level
if level == Shell.ZOOM_ACTIVITY: if level == Shell.ZOOM_ACTIVITY:
@ -218,13 +224,3 @@ class Shell(gobject.GObject):
self._home_window.set_view(HomeWindow.FRIENDS_VIEW) self._home_window.set_view(HomeWindow.FRIENDS_VIEW)
elif level == Shell.ZOOM_MESH: elif level == Shell.ZOOM_MESH:
self._home_window.set_view(HomeWindow.MESH_VIEW) self._home_window.set_view(HomeWindow.MESH_VIEW)
def zoom_in(self):
level = self._zoom_level + 1
if level <= Shell.ZOOM_ACTIVITY:
self._set_zoom_level(level)
def zoom_out(self):
level = self._zoom_level - 1
if level >= Shell.ZOOM_MESH:
self._set_zoom_level(level)

View File

@ -5,7 +5,5 @@
<Alt>n=next <Alt>n=next
<Alt>p=prev <Alt>p=prev
<Alt>c=close <Alt>c=close
f1=!sugar-zoom out f5=!sugar-people
f2=!sugar-zoom in f6=!sugar-activity org.sugar.Terminal
f3=!sugar-people
f4=!sugar-activity org.sugar.Terminal

View File

@ -1,14 +0,0 @@
#!/usr/bin/python
import sys
import dbus
import dbus.glib
bus = dbus.SessionBus()
proxy_obj = bus.get_object('com.redhat.Sugar.Shell', '/com/redhat/Sugar/Shell')
shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.Shell')
if sys.argv[1] == 'in':
shell.zoom_in()
elif sys.argv[1] == 'out':
shell.zoom_out()