http://mulliner.org/bluetooth/xkbdbthid-0.1_src.tar.gz
[xkbdbthid.git] / xkbd-0.8.15_bthid / src / xkbd.c
1 /* 
2    xkbd - xlib based onscreen keyboard.
3
4    Copyright (C) 2001 Matthew Allum
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <signal.h>
22
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
26 #include <X11/extensions/XTest.h>
27 #include <X11/keysym.h>
28 #include <X11/extensions/shape.h>
29 #include "../config.h"
30
31 #include "libXkbd.h"
32
33 #include "structs.h"
34
35 #include "sdp.h"
36 #include "hidcd.h"
37
38 #define DEBUG 1
39
40 #define WIN_NORMAL  1
41 #define WIN_OVERIDE 2
42
43 #define WIN_OVERIDE_AWAYS_TOP 0
44 #define WIN_OVERIDE_NOT_AWAYS_TOP 1
45
46 // bthid
47 extern int es[2];
48 int bthid_pid;
49
50 Display* display; /* ack globals due to sighandlers - another way ? */  
51 Window   win;
52 int      screen_num;    
53
54 enum {
55   WM_UNKNOWN,
56   WM_EHWM_UNKNOWN,
57   WM_METACITY,
58   WM_MATCHBOX,
59 };
60
61 static unsigned char*
62 get_current_window_manager_name (void)
63 {
64   Atom utf8_string, atom, atom_check, type;
65   int result;
66   unsigned char *retval;
67   int format;
68   long nitems;
69   long bytes_after;
70   unsigned char *val;
71   Window *xwindow = NULL;
72
73   atom_check = XInternAtom (display, "_NET_SUPPORTING_WM_CHECK", False);
74
75   XGetWindowProperty (display, 
76                       RootWindow(display, DefaultScreen(display)),
77                       atom_check,
78                       0, 16L, False, XA_WINDOW, &type, &format,
79                       &nitems, &bytes_after, (unsigned char **)&xwindow);
80
81   if (xwindow == NULL)
82       return NULL;
83
84
85   utf8_string = XInternAtom (display, "UTF8_STRING", False);
86   atom = XInternAtom (display, "_NET_WM_NAME", False);
87
88   result = XGetWindowProperty (display,
89                                *xwindow,
90                                atom,
91                                0, 1000L,
92                                False, utf8_string,
93                                &type, &format, &nitems,
94                                &bytes_after, (unsigned char **)&val);
95
96   if (result != Success)
97     return NULL;
98
99   if (type != utf8_string || format !=8 || nitems == 0)
100     {
101       if (val) XFree (val);
102       return NULL;
103     }
104
105   retval = strdup (val);
106
107   XFree (val);
108
109   return retval;
110 }
111
112
113 void handle_sig(int sig)
114 {
115    XWindowAttributes attr;
116    XGetWindowAttributes(display, win, &attr);
117    if (attr.map_state == IsUnmapped ||
118        attr.map_state == IsUnviewable )
119    {
120       XMapWindow(display, win);
121       XRaiseWindow(display,win);
122    } else {
123       XUnmapWindow(display, win);
124    }
125 }
126
127 void version()
128 {
129    printf("Version: %s \n", VERSION);
130 #ifdef USE_XFT 
131    printf("XFT supported\n");
132 #endif
133 #ifdef USE_XPM 
134    printf("XPM supported\n");
135 #endif
136 }
137
138 void usage(void)
139 {
140    printf("Usage: xkbd <options>\n");
141    printf("Options:\n");
142    printf("  -display  <display>\n");
143    printf("  -geometry <geometry>\n");
144 #ifdef USE_XFT 
145    printf("  -font <font name>  Select the xft AA font for xkbd\n");
146 #else
147    printf("  -font <font name>  Select the X11 font for xkbd\n");
148 #endif
149    printf("     ( NOTE: The above will overide the configs font )\n");
150    printf("  -k  <keybaord file> Select the keyboard definition file\n");
151    printf("                      other than" DEFAULTCONFIG "\n");
152    printf("  -xid used for gtk embedding   \n");
153    printf("  -v  version\n");
154    printf("  -h  this help\n\n");
155 }
156
157
158 int main(int argc, char **argv)
159 {
160    char *window_name = "xkbd";
161
162    char *icon_name = "xkbd";
163
164 #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
165 #define MWM_HINTS_DECORATIONS          (1L << 1)
166 #define MWM_DECOR_BORDER               (1L << 1)
167
168    typedef struct
169    {
170      unsigned long       flags;
171      unsigned long       functions;
172      unsigned long       decorations;
173      long                inputMode;
174      unsigned long       status;
175    } PropMotifWmHints ;
176    
177    PropMotifWmHints *mwm_hints;
178
179    XSizeHints size_hints;
180    XWMHints *wm_hints;
181
182    char *display_name = (char *)getenv("DISPLAY");  
183    
184    Xkbd *kb = NULL;
185
186    char *wm_name;
187    int wm_type = WM_UNKNOWN;
188
189    char *geometry = NULL;
190    int xret=0, yret=0, wret=0, hret=0;
191    char *conf_file = NULL;
192    char *font_name = NULL;
193    int cmd_xft_selected = 0; /* ugly ! */
194    int embed = 0;
195    Bool use_normal_win = False;
196    
197    XEvent an_event;
198
199    int done = 0;
200    
201    int i;
202    char userconffile[256];
203    FILE *fp;
204    KeySym mode_switch_ksym;
205
206    // bthid pipe
207    bthid_open();
208         
209          // parent
210    if ((bthid_pid = fork())) {
211       close(0);
212    }
213          // child
214    else {
215       close(1);
216       sdp_open();
217       sdp_add_keyboard();
218       bthid(es[0]);
219       exit(0);
220    }
221
222    for (i=1; argv[i]; i++) {
223       char *arg = argv[i];
224       if (*arg=='-') {
225          switch (arg[1]) {
226             case 'd' : /* display */
227                display_name = argv[i+1];
228                i++;
229                break;
230             case 'g' :
231                geometry = argv[i+1];
232                i++;
233                break; 
234             case 'f':
235                font_name = argv[i+1];
236 #ifdef USE_XFT 
237                cmd_xft_selected = 1;
238 #endif
239                break;
240             case 'o' : /* wm override */
241             case 't' :
242                fprintf( stderr, "Overide redirect support deprciated\n");
243                exit(1);
244                break;
245             case 'k' :
246                conf_file = argv[i+1];
247                i++;
248                break;
249             case 'x' :
250                embed = 1;
251                break;
252             case 'n' :
253                use_normal_win = True;
254                break;
255             case 'v' :
256                version();
257                exit(0);
258                break;
259             default:
260                usage();
261                exit(0);
262                break;
263          }
264       } 
265    }
266
267    display = XOpenDisplay(display_name);
268
269    if (display != NULL) 
270    {
271       Atom wm_protocols[]={ 
272          XInternAtom(display, "WM_DELETE_WINDOW",False),
273          XInternAtom(display, "WM_PROTOCOLS",False),
274          XInternAtom(display, "WM_NORMAL_HINTS", False),
275       };
276
277       Atom window_type_atom =
278          XInternAtom(display, "_NET_WM_WINDOW_TYPE" , False);
279       Atom window_type_toolbar_atom =
280          XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLBAR",False);
281       Atom mwm_atom =
282         XInternAtom(display, "_MOTIF_WM_HINTS",False);
283
284       Atom window_type_dock_atom = 
285         XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK",False);
286
287
288       /* HACK to get libvirtkeys to work without mode_switch */
289
290       screen_num = DefaultScreen(display);
291
292       if  (XKeysymToKeycode(display, XK_Mode_switch) == 0)
293         {
294           int keycode;  
295           int min_kc, max_kc;
296         
297           XDisplayKeycodes(display, &min_kc, &max_kc);
298           
299           for (keycode = min_kc; keycode <= max_kc; keycode++)
300             if (XKeycodeToKeysym (display, keycode, 0) == NoSymbol)
301               {
302                 mode_switch_ksym = XStringToKeysym("Mode_switch");
303                 XChangeKeyboardMapping(display, 
304                                        keycode, 1,
305                                        &mode_switch_ksym, 1);
306                 XSync(display, False);
307               }
308       }
309       
310       wm_name = get_current_window_manager_name ();
311       use_normal_win = True;
312       
313       if (wm_name)
314         {
315           wm_type = WM_EHWM_UNKNOWN;
316           if (!strcmp(wm_name, "metacity"))
317             wm_type = WM_METACITY;
318           else if (!strcmp(wm_name, "matchbox"))
319             {
320
321               use_normal_win = False;
322               wm_type = WM_MATCHBOX;
323             }
324         }
325        
326       win = XCreateSimpleWindow(display,
327                                 RootWindow(display, screen_num),
328                                 0, 0,
329                                 300, 300,
330                                 0, BlackPixel(display, screen_num),
331                                 WhitePixel(display, screen_num));
332       
333       if (geometry != NULL)
334         {
335           XParseGeometry(geometry, &xret, &yret, &wret, &hret );
336         }
337       else
338         {
339           if (wm_type != WM_MATCHBOX)
340             {
341               wret = DisplayWidth(display, screen_num);
342               hret = DisplayHeight(display, screen_num)/4;
343               xret = 0;
344               yret = DisplayHeight(display, screen_num) - hret;
345             }
346         }
347       
348       /* check for user selected keyboard conf file */
349
350       if (conf_file == NULL)
351         {
352           strcpy(userconffile,getenv("HOME"));
353           strcat(userconffile, "/.xkbd");
354
355           if ((fp = fopen(userconffile, "r")) != NULL)
356             {
357               conf_file = (char *)malloc(sizeof(char)*512);
358               if (fgets(conf_file, 512, fp) != NULL)
359                 {
360                   fclose(fp);
361                   if ( conf_file[strlen(conf_file)-1] == '\n')
362                     conf_file[strlen(conf_file)-1] = '\0';
363                 }
364             }
365           else
366             {
367               conf_file = DEFAULTCONFIG;
368             }
369         }
370
371       kb = xkbd_realize(display, win, conf_file, font_name, 0, 0, 
372                         wret, hret, cmd_xft_selected);
373     
374       XResizeWindow(display, win, xkbd_get_width(kb), xkbd_get_height(kb));
375     
376       if (xret || yret)
377          XMoveWindow(display,win,xret,yret);
378     
379       size_hints.flags = PPosition | PSize | PMinSize;
380       size_hints.x = 0;
381       size_hints.y = 0;
382       size_hints.width      =  xkbd_get_width(kb);
383       size_hints.height     =  xkbd_get_height(kb);
384       size_hints.min_width  =  xkbd_get_width(kb);
385       size_hints.min_height =  xkbd_get_height(kb);
386     
387       XSetStandardProperties(display, win, window_name, 
388                              icon_name, 0,
389                              argv, argc, &size_hints);
390     
391       wm_hints = XAllocWMHints();
392       wm_hints->input = False;
393       wm_hints->flags = InputHint;
394       XSetWMHints(display, win, wm_hints );
395
396       /* Tell the WM we dont want no borders */
397       mwm_hints = malloc(sizeof(PropMotifWmHints));
398       memset(mwm_hints, 0, sizeof(PropMotifWmHints));
399       
400       mwm_hints->flags = MWM_HINTS_DECORATIONS;
401       mwm_hints->decorations = 0;
402
403
404       XChangeProperty(display, win, mwm_atom, 
405                       XA_ATOM, 32, PropModeReplace, 
406                       (unsigned char *)mwm_hints, 
407                       PROP_MOTIF_WM_HINTS_ELEMENTS);
408       
409       free(mwm_hints);
410     
411
412       XSetWMProtocols(display, win, wm_protocols, sizeof(wm_protocols) / 
413                       sizeof(Atom));
414
415       if (use_normal_win == False)
416         XChangeProperty(display, win, window_type_atom, XA_ATOM, 32, 
417                         PropModeReplace, 
418                         (unsigned char *) &window_type_toolbar_atom, 1);
419
420       if (embed)
421       {
422          fprintf(stdout, "%i\n", win);
423          fclose(stdout);
424       } else {
425          XMapWindow(display, win);
426       }
427     
428       signal(SIGUSR1, handle_sig); /* for extenal mapping / unmapping */
429     
430       XSelectInput(display, win, 
431                    ExposureMask |
432                    ButtonPressMask |
433                    ButtonReleaseMask |
434                    Button1MotionMask |
435                    StructureNotifyMask |
436                    VisibilityChangeMask);
437  
438       while (!done)
439       {
440          while ( XPending(display) ) 
441          {
442
443             XNextEvent(display, &an_event);
444             xkbd_process(kb, &an_event);
445
446                         
447             switch (an_event.type) {
448                case ClientMessage:
449                   if ((an_event.xclient.message_type == wm_protocols[1])
450                       && (an_event.xclient.data.l[0] == wm_protocols[0])) 
451                      done = 1;
452                   break;
453                case ConfigureNotify:
454                   if ( an_event.xconfigure.width != xkbd_get_width(kb)
455                        || an_event.xconfigure.height != xkbd_get_height(kb))
456                   {
457                      xkbd_resize(kb,
458                                  an_event.xconfigure.width,
459                                  an_event.xconfigure.height );
460                   }
461                   break;
462                case Expose:
463                   xkbd_repaint(kb);
464                   break;
465             }
466          }
467          xkbd_process_repeats(kb);
468          usleep(10000L); /* sleep for a 10th of a second */
469       }
470       xkbd_destroy(kb);
471       XCloseDisplay(display);
472        
473    } else {
474       fprintf(stderr, "%s: cannot connect to X server '%s'\n",
475               argv[0], display_name);
476       exit(1);
477    }
478    exit(0);
479    
480
481 }