📄 matchbox-keyboard-ui.c
字号:
/* * Matchbox Keyboard - A lightweight software keyboard. * * Authored By Matthew Allum <mallum@o-hand.com> * * Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include "matchbox-keyboard.h"#define PROP_MOTIF_WM_HINTS_ELEMENTS 5#define MWM_HINTS_DECORATIONS (1L << 1)#define MWM_DECOR_BORDER (1L << 1)typedef struct{ unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status;} PropMotifWmHints;struct MBKeyboardUI{ Display *xdpy; int xscreen; Window xwin_root, xwin; Pixmap backbuffer; int dpy_width, dpy_height; int xwin_width, xwin_height; int key_uwidth, key_uheight; int base_alloc_width, base_alloc_height; int base_font_pt_size; Bool want_embedding; FakeKey *fakekey; MBKeyboardUIBackend *backend; MBKeyboard *kbd;};static voidmb_kbd_ui_resize(MBKeyboardUI *ui, int width, int height);static intmb_kbd_ui_load_font(MBKeyboardUI *ui);static char*get_current_window_manager_name (MBKeyboardUI *ui){ Atom atom_utf8_string, atom_wm_name, atom_check, type; int result, format; char *val, *retval; unsigned long nitems, bytes_after; Window *support_xwin = NULL; atom_check = XInternAtom (ui->xdpy, "_NET_SUPPORTING_WM_CHECK", False); XGetWindowProperty (ui->xdpy, RootWindow(ui->xdpy, ui->xscreen), atom_check, 0, 16L, False, XA_WINDOW, &type, &format, &nitems, &bytes_after, (unsigned char **)&support_xwin); if (support_xwin == NULL) return NULL; atom_utf8_string = XInternAtom (ui->xdpy, "UTF8_STRING", False); atom_wm_name = XInternAtom (ui->xdpy, "_NET_WM_NAME", False); result = XGetWindowProperty (ui->xdpy, *support_xwin, atom_wm_name, 0, 1000L,False, atom_utf8_string, &type, &format, &nitems, &bytes_after, (unsigned char **)&val); if (result != Success) return NULL; if (type != atom_utf8_string || format !=8 || nitems == 0) { if (val) XFree (val); return NULL; } retval = strdup (val); XFree (val); return retval;}static booleanget_desktop_area(MBKeyboardUI *ui, int *x, int *y, int *width, int *height){ Atom atom_area, type; int result, format; unsigned long nitems, bytes_after; int *geometry = NULL; atom_area = XInternAtom (ui->xdpy, "_NET_WORKAREA", False); result = XGetWindowProperty (ui->xdpy, RootWindow(ui->xdpy, ui->xscreen), atom_area, 0, 16L, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, (unsigned char **)&geometry); if (result != Success || nitems < 4 || geometry == NULL) { if (geometry) XFree(geometry); return False; } if (x) *x = geometry[0]; if (y) *y = geometry[1]; if (width) *width = geometry[2]; if (height) *height = geometry[3]; XFree(geometry); return True;}static voidupdate_display_size(MBKeyboardUI *ui){ XWindowAttributes winattr; XGetWindowAttributes(ui->xdpy, ui->xwin_root, &winattr); /* XXX should actually trap an X error here */ ui->dpy_width = winattr.width; ui->dpy_height = winattr.height; return;}static booleanwant_extended(MBKeyboardUI *ui){ /* Are we in portrait ? */ if (ui->dpy_width > ui->dpy_height) return True; return False;}static booleanget_xevent_timed(Display *dpy, XEvent *event_return, struct timeval *tv){ if (tv->tv_usec == 0 && tv->tv_sec == 0) { XNextEvent(dpy, event_return); return True; } XFlush(dpy); if (XPending(dpy) == 0) { int fd = ConnectionNumber(dpy); fd_set readset; FD_ZERO(&readset); FD_SET(fd, &readset); if (select(fd+1, &readset, NULL, NULL, tv) == 0) return False; else { XNextEvent(dpy, event_return); return True; } } else { XNextEvent(dpy, event_return); return True; }}voidmb_kbd_ui_send_press(MBKeyboardUI *ui, const char *utf8_char_in, int modifiers){ DBG("Sending '%s'", utf8_char_in); fakekey_press(ui->fakekey, (unsigned char*)utf8_char_in, -1, modifiers);}voidmb_kbd_ui_send_keysym_press(MBKeyboardUI *ui, KeySym ks, int modifiers){ fakekey_press_keysym(ui->fakekey, ks, modifiers);}voidmb_kbd_ui_send_release(MBKeyboardUI *ui){ fakekey_release(ui->fakekey);}static voidmb_kdb_ui_unit_key_size(MBKeyboardUI *ui, int *width, int *height){ MBKeyboardLayout *layout; List *row_item, *key_item; MBKeyboardKeyStateType state; const char *face_str; *width = 0; *height = 0; layout = mb_kbd_get_selected_layout(ui->kbd); row_item = mb_kbd_layout_rows(layout); /* * Figure out the base size of a 'regular' single glyph key. */ while (row_item != NULL) { mb_kbd_row_for_each_key(row_item->data, key_item) { MBKeyboardKey *key = key_item->data; if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(key)) continue; mb_kdb_key_foreach_state(key, state) { if (mb_kbd_key_get_face_type(key, state) == MBKeyboardKeyFaceGlyph) { face_str = mb_kbd_key_get_glyph_face(key, state); if (util_utf8_char_cnt(face_str) == 1) { int str_w =0, str_h = 0; ui->backend->text_extents(ui, face_str, &str_w, &str_h); if (str_w > *width) *width = str_w; if (str_h > *height) *height = str_h; } } /* TODO: also need to check height of image keys etc */ } } row_item = util_list_next(row_item); } /* FIXME: hack for small displays */ if (mb_kbd_ui_display_height(ui) <= 320) { *height += 4; }}static voidmb_kbd_ui_min_key_size(MBKeyboardUI *ui, MBKeyboardKey *key, int *width, int *height){ const char *face_str = NULL; int max_w = 0, max_h = 0, state; /* * Figure out how small a key can really be UI wise. */ if (mb_kbd_key_get_req_uwidth(key) || mb_kbd_key_is_blank(key)) { *width = (ui->key_uwidth * mb_kbd_key_get_req_uwidth(key)) / 1000 ; *height = ui->key_uheight; return; } mb_kdb_key_foreach_state(key, state) { if (mb_kbd_key_get_face_type(key, state) == MBKeyboardKeyFaceGlyph) { face_str = mb_kbd_key_get_glyph_face(key, state); ui->backend->text_extents(ui, face_str, width, height); if (*width < max_w) *width = max_w; if (*height < max_h) *height = max_h; } /* XXX else, images etc */ }}voidmb_kbd_ui_allocate_ui_layout(MBKeyboardUI *ui, int *width, int *height){ MBKeyboardLayout *layout; List *row_item, *key_item; int key_y = 0, key_x = 0; int row_y, max_row_key_height, max_row_width; layout = mb_kbd_get_selected_layout(ui->kbd); /* Do an initial run to figure out a 'base' size for single glyph keys */ mb_kdb_ui_unit_key_size(ui, &ui->key_uwidth, &ui->key_uheight); row_item = mb_kbd_layout_rows(layout); row_y = mb_kbd_row_spacing(ui->kbd); max_row_width = 0; /* * First of entire keyboard, basically get the minimum space needed */ while (row_item != NULL) { MBKeyboardRow *row = row_item->data; key_x = mb_kbd_col_spacing(ui->kbd); max_row_key_height = 0; mb_kbd_row_for_each_key(row, key_item) { int key_w, key_h; MBKeyboardKey *key = key_item->data; mb_kbd_key_set_extra_height_pad(key, 0); mb_kbd_key_set_extra_width_pad(key, 0); mb_kbd_key_set_geometry(key, 0, 0, 0, 0); if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(key)) continue; mb_kbd_ui_min_key_size(ui, key, &key_w, &key_h); if (!mb_kbd_key_get_req_uwidth(key) && key_w < ui->key_uwidth) key_w = ui->key_uwidth; if (key_h < ui->key_uheight) key_h = ui->key_uheight; key_y = 0; key_w += 2 * ( mb_kbd_keys_border(ui->kbd) + mb_kbd_keys_margin(ui->kbd) + mb_kbd_keys_pad(ui->kbd) ); key_h += 2 * ( mb_kbd_keys_border(ui->kbd) + mb_kbd_keys_margin(ui->kbd) + mb_kbd_keys_pad(ui->kbd) ); if (key_h > max_row_key_height) max_row_key_height = key_h; mb_kbd_key_set_geometry(key, key_x, key_y, key_w, key_h); key_x += (mb_kbd_col_spacing(ui->kbd) + key_w); } if (key_x > max_row_width) /* key_x now represents row width */ max_row_width = key_x; mb_kbd_row_set_y(row, row_y); row_y += max_row_key_height + mb_kbd_row_spacing(ui->kbd); row_item = util_list_next(row_item); } *height = row_y; row_item = mb_kbd_layout_rows(layout); /* Now pass again allocating any extra space with have left over */ while (row_item != NULL) { MBKeyboardRow *row = row_item->data; int n_fillers = 0, free_space = 0, new_w = 0; mb_kbd_row_for_each_key(row,key_item) { if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(key_item->data)) continue; if (mb_kbd_key_get_fill(key_item->data) || mb_kbd_ui_display_height(ui) <= 320 || mb_kbd_ui_display_width(ui) <= 320 ) n_fillers++; } if (!n_fillers) goto next_row; free_space = max_row_width - mb_kbd_row_width(row); mb_kbd_row_for_each_key(row, key_item) { if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(key_item->data)) continue; if (mb_kbd_key_get_fill(key_item->data) || mb_kbd_ui_display_height(ui) <= 320 || mb_kbd_ui_display_width(ui) <= 320 ) { int old_w; List *nudge_key_item = util_list_next(key_item); old_w = mb_kbd_key_width(key_item->data); new_w = old_w + (free_space/n_fillers); mb_kbd_key_set_geometry(key_item->data, -1, -1, new_w, -1); /* nudge next keys forward */ for (; nudge_key_item != NULL; nudge_key_item = util_list_next(nudge_key_item)) { if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(nudge_key_item->data)) continue; mb_kbd_key_set_geometry(nudge_key_item->data, mb_kbd_key_x(nudge_key_item->data) + (new_w - old_w ), -1, -1, -1); } } } next_row: row_item = util_list_next(row_item); } /* Now center the rows */ row_item = mb_kbd_layout_rows(layout); while (row_item != NULL) { MBKeyboardRow *row = row_item->data; mb_kbd_row_set_x(row, (max_row_width - mb_kbd_row_width(row))/2); row_item = util_list_next(row_item); } *width = max_row_width;}voidmb_kbd_ui_redraw_key(MBKeyboardUI *ui, MBKeyboardKey *key){ ui->backend->redraw_key(ui, key);}static voidmb_kbd_ui_redraw_row(MBKeyboardUI *ui, MBKeyboardRow *row){ List *key_item; mb_kbd_row_for_each_key(row, key_item) { if (!mb_kbd_is_extended(ui->kbd) && mb_kbd_key_get_extended(key_item->data)) continue; mb_kbd_ui_redraw_key(ui, key_item->data); }}voidmb_kbd_ui_swap_buffers(MBKeyboardUI *ui){ XClearWindow(ui->xdpy, ui->xwin); XSync(ui->xdpy, False);}voidmb_kbd_ui_redraw(MBKeyboardUI *ui){ List *row_item; MBKeyboardLayout *layout; MARK(); /* gives backend a chance to clear everything */ ui->backend->pre_redraw(ui); layout = mb_kbd_get_selected_layout(ui->kbd); row_item = mb_kbd_layout_rows(layout); while (row_item != NULL) { MBKeyboardRow *row = row_item->data; mb_kbd_ui_redraw_row(ui, row); row_item = util_list_next(row_item); } mb_kbd_ui_swap_buffers(ui);}voidmb_kbd_ui_show(MBKeyboardUI *ui){ XMapWindow(ui->xdpy, ui->xwin);} static intmb_kbd_ui_resources_create(MBKeyboardUI *ui){#define PROP_MOTIF_WM_HINTS_ELEMENTS 5#define MWM_HINTS_DECORATIONS (1L << 1)#define MWM_DECOR_BORDER (1L << 1) typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status; } PropMotifWmHints ; Atom /* atom_wm_protocols[3], */ atom_NET_WM_WINDOW_TYPE, atom_NET_WM_WINDOW_TYPE_TOOLBAR, atom_NET_WM_WINDOW_TYPE_DOCK, atom_NET_WM_STRUT_PARTIAL, atom_NET_WM_STATE_SKIP_PAGER, atom_NET_WM_STATE_SKIP_TASKBAR, atom_NET_WM_STATE, atom_MOTIF_WM_HINTS; PropMotifWmHints *mwm_hints; XSizeHints size_hints; XWMHints *wm_hints; XSetWindowAttributes win_attr; char *wm_name; boolean have_matchbox_wm = False; boolean have_ewmh_wm = False; /* atom_wm_protocols = { XInternAtom(ui->xdpy, "WM_DELETE_WINDOW",False), XInternAtom(ui->xdpy, "WM_PROTOCOLS",False), XInternAtom(ui->xdpy, "WM_NORMAL_HINTS", False), }; */ atom_NET_WM_WINDOW_TYPE = XInternAtom(ui->xdpy, "_NET_WM_WINDOW_TYPE" , False); atom_NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(ui->xdpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); atom_NET_WM_WINDOW_TYPE_DOCK = XInternAtom(ui->xdpy, "_NET_WM_WINDOW_TYPE_DOCK", False); atom_MOTIF_WM_HINTS = XInternAtom(ui->xdpy, "_MOTIF_WM_HINTS", False); atom_NET_WM_STRUT_PARTIAL = XInternAtom(ui->xdpy, "_NET_WM_STRUT_PARTIAL", False); atom_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(ui->xdpy, "_NET_WM_STATE_SKIP_TASKBAR", False); atom_NET_WM_STATE_SKIP_PAGER = XInternAtom(ui->xdpy, "_NET_WM_STATE_SKIP_PAGER", False); atom_NET_WM_STATE = XInternAtom(ui->xdpy, "_NET_WM_STATE", False); if ((wm_name = get_current_window_manager_name(ui)) != NULL) { have_ewmh_wm = True; /* basically assumed to be Metacity or at least only tested with mcity */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -