]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/gdkmain-fb.c
More proper vt switch handling
[~andy/gtk] / gdk / linux-fb / gdkmain-fb.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/mman.h>
32 #include <sys/ioctl.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <time.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/vt.h>
39 #include <sys/kd.h>
40 #include <errno.h>
41 #include <signal.h>
42
43 #include <sys/socket.h>
44 #include <sys/un.h>
45
46 #include "gdk.h"
47
48 #include "gdkprivate-fb.h"
49 #include "gdkinternals.h"
50 #include "gdkfbmanager.h"
51
52 /* Private variable declarations
53  */
54 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
55                                                      * 0 otherwise.
56                                                      */
57
58 #ifdef G_ENABLE_DEBUG
59 static const GDebugKey gdk_debug_keys[] = {
60   {"misc",          GDK_DEBUG_MISC},
61   {"events",        GDK_DEBUG_EVENTS},
62 };
63
64 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
65
66 #endif /* G_ENABLE_DEBUG */
67
68 GdkArgDesc _gdk_windowing_args[] = {
69   { NULL }
70 };
71
72 static const GScannerConfig     fb_modes_scanner_config =
73 {
74   (
75    " \t\n"
76    )                    /* cset_skip_characters */,
77   (
78    G_CSET_a_2_z
79    G_CSET_A_2_Z
80    )                    /* cset_identifier_first */,
81   (
82    G_CSET_a_2_z
83    "_-0123456789"
84    G_CSET_A_2_Z
85    )                    /* cset_identifier_nth */,
86   ( "#\n" )             /* cpair_comment_single */,
87   
88   FALSE                  /* case_sensitive */,
89   
90   FALSE                 /* skip_comment_multi */,
91   TRUE                  /* skip_comment_single */,
92   FALSE                 /* scan_comment_multi */,
93   TRUE                  /* scan_identifier */,
94   TRUE                  /* scan_identifier_1char */,
95   FALSE                 /* scan_identifier_NULL */,
96   TRUE                  /* scan_symbols */,
97   FALSE                 /* scan_binary */,
98   FALSE                 /* scan_octal */,
99   FALSE                  /* scan_float */,
100   FALSE                  /* scan_hex */,
101   FALSE                 /* scan_hex_dollar */,
102   FALSE                 /* scan_string_sq */,
103   TRUE                  /* scan_string_dq */,
104   TRUE                  /* numbers_2_int */,
105   FALSE                 /* int_2_float */,
106   FALSE                 /* identifier_2_string */,
107   TRUE                  /* char_2_token */,
108   FALSE                 /* symbol_2_token */,
109   FALSE                 /* scope_0_fallback */,
110 };
111
112 enum {
113   FB_MODE,
114   FB_ENDMODE,
115   FB_GEOMETRY,
116   FB_TIMINGS,
117   FB_LACED,
118   FB_HSYNC,
119   FB_VSYNC,
120   FB_CSYNC,
121   FB_EXTSYNC,
122   FB_DOUBLE,
123   FB_ACCEL
124 };
125
126 char *fb_modes_keywords[] =
127 {
128   "mode",
129   "endmode",
130   "geometry",
131   "timings",
132   "laced",
133   "hsync",
134   "vsync",
135   "csync",
136   "extsync",
137   "double",
138   "accel"
139 };
140
141 static int
142 fb_modes_parse_mode (GScanner *scanner,
143                      struct fb_var_screeninfo *modeinfo,
144                      char *specified_modename)
145 {
146   guint token;
147   int keyword;
148   int i;
149   char *modename;
150   int geometry[5];
151   int timings[7];
152   int vsync=0, hsync=0, csync=0, extsync=0, doublescan=0, laced=0, accel=1;
153   int found_geometry = 0;
154   int found_timings = 0;
155     
156   token = g_scanner_get_next_token (scanner);
157   if (token != G_TOKEN_SYMBOL)
158     return -1;
159   
160   keyword = GPOINTER_TO_INT (scanner->value.v_symbol);
161   if (keyword != FB_MODE)
162     return -1;
163
164   token = g_scanner_get_next_token (scanner);
165   if (token != G_TOKEN_STRING)
166     return -1;
167
168   modename = g_strdup (scanner->value.v_string);
169   
170   token = g_scanner_get_next_token (scanner);
171   if (token != G_TOKEN_SYMBOL)
172     {
173       g_free (modename);
174       return -1; /* Not a valid keyword */
175     }
176   keyword = GPOINTER_TO_INT (scanner->value.v_symbol);
177   while ( keyword != FB_ENDMODE )
178     {
179
180       switch (GPOINTER_TO_INT (scanner->value.v_symbol))
181         {
182         case FB_GEOMETRY:
183           for (i = 0; i < 5;i++) {
184             token = g_scanner_get_next_token (scanner);
185             if (token != G_TOKEN_INT)
186               {
187                 g_free (modename);
188                 return -1; /* need a integer */
189               }
190             geometry[i] = scanner->value.v_int;
191           }
192           found_geometry = TRUE;
193           break;
194         case FB_TIMINGS:
195           for (i = 0; i < 7; i++) {
196             token = g_scanner_get_next_token (scanner);
197             if (token != G_TOKEN_INT)
198               {
199                 g_free (modename);
200                 return -1; /* need a integer */
201               }
202             timings[i] = scanner->value.v_int;
203           }
204           found_timings = TRUE;
205           break;
206         case FB_LACED:
207           token = g_scanner_get_next_token (scanner);
208           if (token != G_TOKEN_IDENTIFIER)
209               {
210                 g_free (modename);
211                 return -1;
212               }
213           if (g_ascii_strcasecmp (scanner->value.v_identifier, "true")==0)
214             laced = 1;
215           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "false")==0)
216             laced = 0;
217           else
218             {
219               g_free (modename);
220               return -1;
221             }
222           break;
223         case FB_EXTSYNC:
224           token = g_scanner_get_next_token (scanner);
225           if (token != G_TOKEN_IDENTIFIER)
226               {
227                 g_free (modename);
228                 return -1;
229               }
230           if (g_ascii_strcasecmp (scanner->value.v_identifier, "true")==0)
231             extsync = 1;
232           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "false")==0)
233             extsync = 0;
234           else
235             {
236               g_free (modename);
237               return -1;
238             }
239           break;
240         case FB_DOUBLE:
241           token = g_scanner_get_next_token (scanner);
242           if (token != G_TOKEN_IDENTIFIER)
243               {
244                 g_free (modename);
245                 return -1;
246               }
247           if (g_ascii_strcasecmp (scanner->value.v_identifier, "true")==0)
248             doublescan = 1;
249           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "false")==0)
250             doublescan = 0;
251           else
252             {
253               g_free (modename);
254               return -1;
255             }
256           break;
257         case FB_VSYNC:
258           token = g_scanner_get_next_token (scanner);
259           if (token != G_TOKEN_IDENTIFIER)
260               {
261                 g_free (modename);
262                 return -1;
263               }
264           if (g_ascii_strcasecmp (scanner->value.v_identifier, "high")==0)
265             vsync = 1;
266           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "low")==0)
267             vsync = 0;
268           else
269             {
270               g_free (modename);
271               return -1;
272             }
273           break;
274         case FB_HSYNC:
275           token = g_scanner_get_next_token (scanner);
276           if (token != G_TOKEN_IDENTIFIER)
277             {
278               g_free (modename);
279               return -1;
280             }
281           if (g_ascii_strcasecmp (scanner->value.v_identifier, "high")==0)
282             hsync = 1;
283           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "low")==0)
284             hsync = 0;
285           else
286             {
287               g_free (modename);
288               return -1;
289             }
290           break;
291         case FB_CSYNC:
292           token = g_scanner_get_next_token (scanner);
293           if (token != G_TOKEN_IDENTIFIER)
294             {
295               g_free (modename);
296               return -1;
297             }
298           if (g_ascii_strcasecmp (scanner->value.v_identifier, "high")==0)
299             csync = 1;
300           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "low")==0)
301             csync = 0;
302           else
303             {
304               g_free (modename);
305               return -1;
306             }
307           break;
308         case FB_ACCEL:
309           token = g_scanner_get_next_token (scanner);
310           if (token != G_TOKEN_IDENTIFIER)
311             {
312               g_free (modename);
313               return -1;
314             }
315           if (g_ascii_strcasecmp (scanner->value.v_identifier, "false")==0)
316             accel = 0;
317           else if (g_ascii_strcasecmp (scanner->value.v_identifier, "true")==0)
318             accel = 1;
319           else
320             {
321               g_free (modename);
322               return -1;
323             }
324           break;
325         }
326       
327       token = g_scanner_get_next_token (scanner);
328       if (token != G_TOKEN_SYMBOL)
329         {
330           g_free (modename);
331           return -1; /* Not a valid keyword */
332         }
333       keyword = GPOINTER_TO_INT (scanner->value.v_symbol);
334     }
335
336   if (strcmp (modename, specified_modename)== 0) {
337     /* we really should be parsing for rgba. regardless, if rgba isn't found,
338      * we can't assume that the original colors are valid for the new mode */
339     memset (&modeinfo->red, 0, sizeof (modeinfo->red));
340     memset (&modeinfo->green, 0, sizeof (modeinfo->green));
341     memset (&modeinfo->blue, 0, sizeof (modeinfo->blue));
342     memset (&modeinfo->transp, 0, sizeof (modeinfo->transp));
343
344     if (!found_geometry)
345       g_warning ("Geometry not specified");
346
347     if (found_geometry)
348       {
349         modeinfo->xres = geometry[0];
350         modeinfo->yres = geometry[1];
351         modeinfo->xres_virtual = geometry[2];
352         modeinfo->yres_virtual = geometry[3];
353         modeinfo->bits_per_pixel = geometry[4];
354       }
355     
356     if (!found_timings)
357       g_warning ("Timing not specified");
358     
359     if (found_timings)
360       {
361         modeinfo->pixclock = timings[0];
362         modeinfo->left_margin = timings[1];
363         modeinfo->right_margin = timings[2];
364         modeinfo->upper_margin = timings[3];
365         modeinfo->lower_margin = timings[4];
366         modeinfo->hsync_len = timings[5];
367         modeinfo->vsync_len = timings[6];
368         
369         modeinfo->vmode = 0;
370         if (laced)
371           modeinfo->vmode |= FB_VMODE_INTERLACED;
372         if (doublescan)
373           modeinfo->vmode |= FB_VMODE_DOUBLE;
374           
375         modeinfo->sync = 0;
376         if (hsync)
377           modeinfo->sync |= FB_SYNC_HOR_HIGH_ACT;
378         if (vsync)
379           modeinfo->sync |= FB_SYNC_VERT_HIGH_ACT;
380         if (accel)
381           modeinfo->accel_flags = FB_ACCELF_TEXT;
382         else
383           modeinfo->accel_flags = 0;
384       }
385
386     g_free (modename);
387     return 1;
388   }
389   
390   g_free (modename);
391
392   return 0;
393 }
394
395 static int
396 gdk_fb_setup_mode_from_name (struct fb_var_screeninfo *modeinfo,
397                              char *modename)
398 {
399   GScanner *scanner;
400   char *filename;
401   gint result;
402   int fd, i;
403   int retval;
404
405   retval = 0;
406   
407   filename = "/etc/fb.modes";
408   
409   fd = open (filename, O_RDONLY);
410   if (fd < 0)
411     {
412       g_warning ("Cannot read %s", filename);
413       return retval;
414     }
415   
416   scanner = g_scanner_new ((GScannerConfig *) &fb_modes_scanner_config);
417   scanner->input_name = filename;
418
419   for (i = 0; i < sizeof(fb_modes_keywords)/sizeof(fb_modes_keywords[0]); i++)
420     g_scanner_scope_add_symbol (scanner, 0, fb_modes_keywords[i], GINT_TO_POINTER (i));
421
422   g_scanner_input_file (scanner, fd);
423   
424   while (1) {
425     if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF) {
426       break;
427     } 
428     result = fb_modes_parse_mode (scanner, modeinfo, modename);
429       
430     if (result < 0) {
431       g_warning ("parse error in %s at line %d", filename, scanner->line);
432       break;
433     }
434     if (result > 0)
435       {
436         retval = 1;
437         break;
438       }
439   }
440   
441   g_scanner_destroy (scanner);
442   
443   close (fd);
444   
445   return retval;
446 }
447   
448
449 static int
450 gdk_fb_set_mode (GdkFBDisplay *display)
451 {
452   char *env, *end;
453   int depth, height, width;
454   gboolean changed;
455   
456   if (ioctl (display->fb_fd, FBIOGET_VSCREENINFO, &display->modeinfo) < 0)
457     return -1;
458
459   display->orig_modeinfo = display->modeinfo;
460
461   changed = FALSE;
462   
463   env = getenv ("GDK_DISPLAY_MODE");
464   if (env)
465     {
466       if (gdk_fb_setup_mode_from_name (&display->modeinfo, env))
467         changed = TRUE;
468       else
469         g_warning ("Couldn't find mode named '%s'", env);
470     }
471
472   env = getenv ("GDK_DISPLAY_DEPTH");
473   if (env)
474     {
475       depth = strtol (env, &end, 10);
476       if (env != end)
477         {
478           changed = TRUE;
479           display->modeinfo.bits_per_pixel = depth;
480         }
481     }
482   
483   env = getenv ("GDK_DISPLAY_WIDTH");
484   if (env)
485     {
486       width = strtol (env, &end, 10);
487       if (env != end)
488         {
489           changed = TRUE;
490           display->modeinfo.xres = width;
491           display->modeinfo.xres_virtual = width;
492         }
493     }
494     
495   env = getenv ("GDK_DISPLAY_HEIGHT");
496   if (env)
497     {
498       height = strtol (env, &end, 10);
499       if (env != end)
500         {
501           changed = TRUE;
502           display->modeinfo.yres = height;
503           display->modeinfo.yres_virtual = height;
504         }
505     }
506
507   if (changed &&
508       (ioctl (display->fb_fd, FBIOPUT_VSCREENINFO, &display->modeinfo) < 0))
509     {
510       g_warning ("Couldn't set specified mode");
511       return -1;
512     }
513   
514   /* ask for info back to make sure of what we got */
515   if (ioctl (display->fb_fd, FBIOGET_VSCREENINFO, &display->modeinfo) < 0)
516     {
517       g_warning ("Error getting var screen info");
518       return -1;
519     }
520   
521   if (ioctl (display->fb_fd, FBIOGET_FSCREENINFO, &display->sinfo) < 0)
522     {
523       g_warning ("Error getting fixed screen info");
524       return -1;
525     }
526   return 0;
527 }
528
529 #ifdef ENABLE_FB_MANAGER
530 static void
531 gdk_fb_switch_from (void)
532 {
533   g_print ("Switch from\n");
534   gdk_shadow_fb_stop_updates ();
535   gdk_fb_mouse_close ();
536   gdk_fb_keyboard_close ();
537 }
538
539 static void
540 gdk_fb_switch_to (void)
541 {
542   g_print ("switch_to\n");
543   gdk_shadow_fb_update (0, 0, 
544                         gdk_display->fb_width, 
545                         gdk_display->fb_height);
546
547   if (!gdk_fb_keyboard_open ())
548     g_warning ("Failed to re-initialize keyboard");
549   
550   if (!gdk_fb_mouse_open ())
551     g_warning ("Failed to re-initialize mouse");
552
553 }
554
555
556 static gboolean
557 gdk_fb_manager_callback (GIOChannel *gioc,
558                          GIOCondition cond,
559                          gpointer data)
560 {
561   struct FBManagerMessage msg;
562   GdkFBDisplay *display;
563   int res;
564
565   display = data;
566
567   res = recv (display->manager_fd, &msg, sizeof (msg), 0);
568
569   if (res==0)
570     {
571       g_source_remove (gdk_display->manager_tag);
572       /*g_io_channel_unref (kb->io);*/
573       close (gdk_display->manager_fd);
574
575     }
576
577   if (res != sizeof (msg))
578     {
579       g_warning ("Got wrong size message");
580       return TRUE;
581     }
582   
583   switch (msg.msg_type)
584     {
585     case FB_MANAGER_SWITCH_FROM:
586       g_print ("Got switch from message\n");
587       display->manager_blocked = TRUE;
588       gdk_fb_switch_from ();
589       msg.msg_type = FB_MANAGER_ACK;
590       send (display->manager_fd, &msg, sizeof (msg), 0);
591       break;
592     case FB_MANAGER_SWITCH_TO:
593       g_print ("Got switch to message\n");
594       display->manager_blocked = FALSE;
595       gdk_fb_switch_to ();
596       break;
597     default:
598       g_warning ("Got unknown message");
599     }
600   return TRUE;
601 }
602
603 #endif /* ENABLE_FB_MANAGER */
604
605 static void
606 gdk_fb_manager_connect (GdkFBDisplay *display)
607 {
608 #ifdef ENABLE_FB_MANAGER
609   int fd;
610   struct sockaddr_un addr;
611   struct msghdr msg = {0};
612   struct cmsghdr *cmsg;
613   struct ucred credentials;
614   struct FBManagerMessage init_msg;
615   struct iovec iov;
616   char buf[CMSG_SPACE (sizeof (credentials))];  /* ancillary data buffer */
617   int *fdptr;
618   int res;
619
620   display->manager_blocked = FALSE;
621   display->manager_fd = -1;
622
623   fd = socket (PF_UNIX, SOCK_STREAM, 0);
624   
625   g_print ("socket: %d\n", fd);
626
627   if (fd < 0)
628     return;
629
630   addr.sun_family = AF_UNIX;
631   strcpy (addr.sun_path, "/tmp/.fb.manager");
632
633   if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) 
634     {
635       g_print ("connect failed\n");
636       close (fd);
637       return;
638     }
639   
640   credentials.pid = getpid ();
641   credentials.uid = geteuid ();
642   credentials.gid = getegid ();
643
644   init_msg.msg_type = FB_MANAGER_NEW_CLIENT;
645   iov.iov_base = &init_msg;
646   iov.iov_len = sizeof (init_msg);
647
648   msg.msg_name = NULL;
649   msg.msg_namelen = 0;
650   msg.msg_iov = &iov;
651   msg.msg_iovlen = 1;
652   msg.msg_control = buf;
653   msg.msg_controllen = sizeof buf;
654   cmsg = CMSG_FIRSTHDR(&msg);
655   cmsg->cmsg_level = SOL_SOCKET;
656   cmsg->cmsg_type = SCM_CREDENTIALS;
657   cmsg->cmsg_len = CMSG_LEN (sizeof (credentials));
658   /* Initialize the payload: */
659   fdptr = (int *)CMSG_DATA (cmsg);
660   memcpy (fdptr, &credentials, sizeof (credentials));
661   /* Sum of the length of all control messages in the buffer: */
662   msg.msg_controllen = cmsg->cmsg_len;
663
664   res = sendmsg (fd, &msg, 0);
665
666   display->manager_fd = fd;
667   display->manager_blocked = TRUE;
668
669   display->manager_tag = g_io_add_watch (g_io_channel_unix_new (fd),
670                                          G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
671                                          gdk_fb_manager_callback,
672                                          display);
673
674   init_msg.msg_type = FB_MANAGER_REQUEST_SWITCH_TO_PID;
675   init_msg.data = getpid ();
676
677   /* Request a switch-to */
678   send (fd, &init_msg, sizeof (init_msg), 0);
679 #endif
680 }
681
682 static void
683 gdk_fb_switch (int sig)
684 {
685   if (sig == SIGUSR1)
686     {
687       ioctl (gdk_display->tty_fd, VT_RELDISP, 1);
688       _gdk_fb_is_active_vt = FALSE;
689       gdk_shadow_fb_stop_updates ();
690       gdk_fb_mouse_close ();
691       gdk_fb_keyboard_close ();
692     }
693   else
694     {
695       GdkColormap *cmap;
696       ioctl (gdk_display->tty_fd, VT_RELDISP, VT_ACKACQ);
697       _gdk_fb_is_active_vt = TRUE;
698
699       /* XXX: is it dangerous to put all this stuff in a signal handler? */
700       cmap = gdk_screen_get_default_colormap (_gdk_screen);
701       gdk_colormap_change (cmap, cmap->size);
702
703       gdk_shadow_fb_update (0, 0,
704                             gdk_display->fb_width,
705                             gdk_display->fb_height);
706
707       if (!gdk_fb_keyboard_open ())
708         g_warning ("Failed to re-initialize keyboard");
709
710       if (!gdk_fb_mouse_open ())
711         g_warning ("Failed to re-initialize mouse");
712
713       gdk_fb_redraw_all ();
714     }
715 }
716
717 static GdkFBDisplay *
718 gdk_fb_display_new ()
719 {
720   GdkFBDisplay *display;
721   gchar *fb_filename;
722   struct vt_stat vs;
723   struct vt_mode vtm;
724   int vt, n;
725   gchar *s, *send;
726   char buf[32];
727
728   display = g_new0 (GdkFBDisplay, 1);
729
730   display->console_fd = open ("/dev/console", O_RDWR);
731   if (display->console_fd < 0)
732     {
733       g_warning ("Can't open /dev/console: %s", strerror (errno));
734       g_free (display);
735       return NULL;
736     }
737   
738   ioctl (display->console_fd, VT_GETSTATE, &vs);
739   display->start_vt = vs.v_active;
740
741   vt = display->start_vt;
742   s = getenv("GDK_VT");
743   if (s)
744     {
745       if (g_ascii_strcasecmp ("new", s)==0)
746         {
747           n = ioctl (display->console_fd, VT_OPENQRY, &vt);
748           if (n < 0 || vt == -1)
749             g_error("Cannot allocate new VT");
750         }
751       else
752         {
753           vt = strtol (s, &send, 10);
754           if (s==send)
755             {
756               g_warning ("Cannot parse GDK_VT");
757               vt = display->start_vt;
758             }
759         }
760       
761     }
762
763   display->vt = vt;
764   
765   /* Switch to the new VT */
766   if (vt != display->start_vt)
767     {
768       ioctl (display->console_fd, VT_ACTIVATE, vt);
769       ioctl (display->console_fd, VT_WAITACTIVE, vt);
770     }
771   
772   /* Open the tty */
773   g_snprintf (buf, sizeof(buf), "/dev/tty%d", vt);
774   display->tty_fd = open (buf, O_RDWR|O_NONBLOCK);
775   if (display->tty_fd < 0)
776     {
777       g_warning ("Can't open %s: %s", buf, strerror (errno));
778       close (display->console_fd);
779       g_free (display);
780       return NULL;
781     }
782
783   /* set up switch signals */
784   if (ioctl (display->tty_fd, VT_GETMODE, &vtm) >= 0)
785     {
786       signal (SIGUSR1, gdk_fb_switch);
787       signal (SIGUSR2, gdk_fb_switch);
788       vtm.mode = VT_PROCESS;
789       vtm.waitv = 0;
790       vtm.relsig = SIGUSR1;
791       vtm.acqsig = SIGUSR2;
792       ioctl (display->tty_fd, VT_SETMODE, &vtm);
793     }
794   _gdk_fb_is_active_vt = TRUE;
795   
796   fb_filename = gdk_get_display ();
797   display->fb_fd = open (fb_filename, O_RDWR);
798   if (display->fb_fd < 0)
799     {
800       g_warning ("Can't open %s: %s", fb_filename, strerror (errno));
801       g_free (fb_filename);
802       close (display->tty_fd);
803       close (display->console_fd);
804       g_free (display);
805       return NULL;
806     }
807   g_free (fb_filename);
808
809   if (gdk_fb_set_mode (display) < 0)
810     {
811       close (display->fb_fd);
812       close (display->tty_fd);
813       close (display->console_fd);
814       g_free (display);
815       return NULL;
816     }
817
818   /* Disable normal text on the console */
819   ioctl (display->fb_fd, KDSETMODE, KD_GRAPHICS);
820
821   ioctl (display->fb_fd, FBIOBLANK, 0);
822
823   /* We used to use sinfo.smem_len, but that seemed to be broken in many cases */
824   display->fb_mmap = mmap (NULL,
825                            display->modeinfo.yres * display->sinfo.line_length,
826                            PROT_READ|PROT_WRITE,
827                            MAP_SHARED,
828                            display->fb_fd,
829                            0);
830   g_assert (display->fb_mmap != MAP_FAILED);
831
832   if (display->sinfo.visual == FB_VISUAL_TRUECOLOR)
833     {
834       display->red_byte = display->modeinfo.red.offset >> 3;
835       display->green_byte = display->modeinfo.green.offset >> 3;
836       display->blue_byte = display->modeinfo.blue.offset >> 3;
837     }
838
839 #ifdef ENABLE_SHADOW_FB
840   if (_gdk_fb_screen_angle % 2 == 0)
841     {
842       display->fb_width = display->modeinfo.xres;
843       display->fb_height = display->modeinfo.yres;
844     } 
845   else
846     {
847       display->fb_width = display->modeinfo.yres;
848       display->fb_height = display->modeinfo.xres;
849     }
850   display->fb_stride =
851     display->fb_width * (display->modeinfo.bits_per_pixel / 8);
852   display->fb_mem = g_malloc(display->fb_height * display->fb_stride);
853 #else
854   display->fb_mem = display->fb_mmap;
855   display->fb_width = display->modeinfo.xres;
856   display->fb_height = display->modeinfo.yres;
857   display->fb_stride = display->sinfo.line_length;
858 #endif
859
860   return display;
861 }
862
863 static void
864 gdk_fb_display_destroy (GdkFBDisplay *display)
865 {
866   /* Restore old framebuffer mode */
867   ioctl (display->fb_fd, FBIOPUT_VSCREENINFO, &display->orig_modeinfo);
868   
869   /* Enable normal text on the console */
870   ioctl (display->fb_fd, KDSETMODE, KD_TEXT);
871   
872   munmap (display->fb_mmap, display->modeinfo.yres * display->sinfo.line_length);
873   close (display->fb_fd);
874
875   ioctl (display->console_fd, VT_ACTIVATE, display->start_vt);
876   ioctl (display->console_fd, VT_WAITACTIVE, display->start_vt);
877   if (display->vt != display->start_vt)
878     ioctl (display->console_fd, VT_DISALLOCATE, display->vt);
879   
880   close (display->tty_fd);
881   close (display->console_fd);
882   g_free (display);
883 }
884
885 void
886 _gdk_windowing_init (int *argc, char ***argv)
887 {
888   if (gdk_initialized)
889     return;
890
891   /* Create new session and become session leader */
892   setsid();
893
894   gdk_display = gdk_fb_display_new ();
895
896   if (!gdk_display)
897     return;
898
899   gdk_shadow_fb_init ();
900   
901   gdk_fb_manager_connect (gdk_display);
902
903   if (!gdk_fb_keyboard_init (!gdk_display->manager_blocked))
904     {
905       g_warning ("Failed to initialize keyboard");
906       gdk_fb_display_destroy (gdk_display);
907       gdk_display = NULL;
908       return;
909     }
910   
911   if (!gdk_fb_mouse_init (!gdk_display->manager_blocked))
912     {
913       g_warning ("Failed to initialize mouse");
914       gdk_fb_keyboard_close ();
915       gdk_fb_display_destroy (gdk_display);
916       gdk_display = NULL;
917       return;
918     }
919
920   /* Although atexit is evil, we need it here because otherwise the
921    * keyboard is left in a bad state. you can still run 'reset' but
922    * that gets annoying after running testgtk for the 20th time.
923    */
924   g_atexit(_gdk_windowing_exit);
925
926   gdk_initialized = TRUE;
927
928   _gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
929
930 }
931
932 void
933 _gdk_windowing_set_default_display (GdkDisplay *display)
934 {
935 }
936
937 /*
938  *--------------------------------------------------------------
939  * gdk_pointer_grab
940  *
941  *   Grabs the pointer to a specific window
942  *
943  * Arguments:
944  *   "window" is the window which will receive the grab
945  *   "owner_events" specifies whether events will be reported as is,
946  *     or relative to "window"
947  *   "event_mask" masks only interesting events
948  *   "confine_to" limits the cursor movement to the specified window
949  *   "cursor" changes the cursor for the duration of the grab
950  *   "time" specifies the time
951  *
952  * Results:
953  *
954  * Side effects:
955  *   requires a corresponding call to gdk_pointer_ungrab
956  *
957  *--------------------------------------------------------------
958  */
959
960 GdkGrabStatus
961 gdk_pointer_grab (GdkWindow *     window,
962                   gint            owner_events,
963                   GdkEventMask    event_mask,
964                   GdkWindow *     confine_to,
965                   GdkCursor *     cursor,
966                   guint32         time)
967 {
968   return gdk_fb_pointer_grab (window,
969                               owner_events,
970                               event_mask,
971                               confine_to,
972                               cursor,
973                               time, FALSE);
974 }
975
976 static gboolean _gdk_fb_pointer_implicit_grab = FALSE;
977
978 GdkGrabStatus
979 gdk_fb_pointer_grab (GdkWindow *          window,
980                      gint                 owner_events,
981                      GdkEventMask         event_mask,
982                      GdkWindow *          confine_to,
983                      GdkCursor *          cursor,
984                      guint32              time,
985                      gboolean             implicit_grab)
986 {
987   g_return_val_if_fail (window != NULL, 0);
988   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
989   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
990
991   if (_gdk_fb_pointer_grab_window)
992     {
993       if (implicit_grab && !_gdk_fb_pointer_implicit_grab)
994         return GDK_GRAB_ALREADY_GRABBED;
995
996       gdk_pointer_ungrab (time);
997     }
998
999   gdk_fb_window_send_crossing_events (NULL,
1000                                       window,
1001                                       GDK_CROSSING_GRAB);  
1002
1003   if (event_mask & GDK_BUTTON_MOTION_MASK)
1004       event_mask |=
1005         GDK_BUTTON1_MOTION_MASK |
1006         GDK_BUTTON2_MOTION_MASK |
1007         GDK_BUTTON3_MOTION_MASK;
1008   
1009   _gdk_fb_pointer_implicit_grab = implicit_grab;
1010
1011   _gdk_fb_pointer_grab_window = gdk_window_ref (window);
1012   _gdk_fb_pointer_grab_owner_events = owner_events;
1013
1014   _gdk_fb_pointer_grab_confine = confine_to ? gdk_window_ref (confine_to) : NULL;
1015   _gdk_fb_pointer_grab_events = event_mask;
1016   _gdk_fb_pointer_grab_cursor = cursor ? gdk_cursor_ref (cursor) : NULL;
1017
1018
1019   
1020   if (cursor)
1021     gdk_fb_cursor_reset ();
1022
1023   return GDK_GRAB_SUCCESS;
1024 }
1025
1026 /*
1027  *--------------------------------------------------------------
1028  * gdk_display_pointer_ungrab
1029  *
1030  *   Releases any pointer grab
1031  *
1032  * Arguments:
1033  *
1034  * Results:
1035  *
1036  * Side effects:
1037  *
1038  *--------------------------------------------------------------
1039  */
1040
1041 void
1042 gdk_display_pointer_ungrab (GdkDisplay *display,
1043                             guint32     time)
1044 {
1045   gdk_fb_pointer_ungrab (time, FALSE);
1046 }
1047
1048 void
1049 gdk_fb_pointer_ungrab (guint32 time, gboolean implicit_grab)
1050 {
1051   gboolean have_grab_cursor = _gdk_fb_pointer_grab_cursor && 1;
1052   GdkWindow *mousewin;
1053   GdkWindow *old_grab_window;
1054   
1055   if (!_gdk_fb_pointer_grab_window)
1056     return;
1057
1058   if (implicit_grab && !_gdk_fb_pointer_implicit_grab)
1059     return;
1060
1061   if (_gdk_fb_pointer_grab_confine)
1062     gdk_window_unref (_gdk_fb_pointer_grab_confine);
1063   _gdk_fb_pointer_grab_confine = NULL;
1064
1065   if (_gdk_fb_pointer_grab_cursor)
1066     gdk_cursor_unref (_gdk_fb_pointer_grab_cursor);
1067   _gdk_fb_pointer_grab_cursor = NULL;
1068
1069   if (have_grab_cursor)
1070     gdk_fb_cursor_reset ();
1071
1072   old_grab_window = _gdk_fb_pointer_grab_window;
1073   
1074   _gdk_fb_pointer_grab_window = NULL;
1075
1076   _gdk_fb_pointer_implicit_grab = FALSE;
1077
1078   mousewin = gdk_window_at_pointer (NULL, NULL);
1079   gdk_fb_window_send_crossing_events (old_grab_window,
1080                                       mousewin,
1081                                       GDK_CROSSING_UNGRAB);
1082   
1083   if (old_grab_window)
1084     gdk_window_unref (old_grab_window);
1085 }
1086
1087 /*
1088  *--------------------------------------------------------------
1089  * gdk_display_pointer_is_grabbed
1090  *
1091  *   Tell wether there is an active x pointer grab in effect
1092  *
1093  * Arguments:
1094  *
1095  * Results:
1096  *
1097  * Side effects:
1098  *
1099  *--------------------------------------------------------------
1100  */
1101
1102 gint
1103 gdk_display_pointer_is_grabbed (GdkDisplay *display)
1104 {
1105   return _gdk_fb_pointer_grab_window != NULL;
1106 }
1107
1108 /*
1109  *--------------------------------------------------------------
1110  * gdk_keyboard_grab
1111  *
1112  *   Grabs the keyboard to a specific window
1113  *
1114  * Arguments:
1115  *   "window" is the window which will receive the grab
1116  *   "owner_events" specifies whether events will be reported as is,
1117  *     or relative to "window"
1118  *   "time" specifies the time
1119  *
1120  * Results:
1121  *
1122  * Side effects:
1123  *   requires a corresponding call to gdk_keyboard_ungrab
1124  *
1125  *--------------------------------------------------------------
1126  */
1127
1128 GdkGrabStatus
1129 gdk_keyboard_grab (GdkWindow  *window,
1130                    gint        owner_events,
1131                    guint32     time)
1132 {
1133   g_return_val_if_fail (window != NULL, 0);
1134   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1135
1136   if (_gdk_fb_pointer_grab_window)
1137     gdk_keyboard_ungrab (time);
1138
1139   _gdk_fb_keyboard_grab_window = gdk_window_ref (window);
1140   _gdk_fb_keyboard_grab_owner_events = owner_events;
1141   
1142   return GDK_GRAB_SUCCESS;
1143 }
1144
1145 /*
1146  *--------------------------------------------------------------
1147  * gdk_display_keyboard_ungrab
1148  *
1149  *   Releases any keyboard grab
1150  *
1151  * Arguments:
1152  *
1153  * Results:
1154  *
1155  * Side effects:
1156  *
1157  *--------------------------------------------------------------
1158  */
1159
1160 void
1161 gdk_display_keyboard_ungrab (GdkDisplay *display,
1162                              guint32     time)
1163 {
1164   if (_gdk_fb_keyboard_grab_window)
1165     gdk_window_unref (_gdk_fb_keyboard_grab_window);
1166   _gdk_fb_keyboard_grab_window = NULL;
1167 }
1168
1169 gboolean
1170 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
1171                                    GdkWindow **grab_window,
1172                                    gboolean   *owner_events)
1173 {
1174   if (_gdk_fb_pointer_grab_window)
1175     {
1176       if (grab_window)
1177         *grab_window = (GdkWindow *)_gdk_fb_pointer_grab_window;
1178       if (owner_events)
1179         *owner_events = _gdk_fb_pointer_grab_owner_events;
1180       
1181       return TRUE;
1182     }
1183   else
1184     return FALSE;
1185 }
1186
1187 gboolean
1188 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
1189                                     GdkWindow **grab_window,
1190                                     gboolean   *owner_events)
1191 {
1192   if (_gdk_fb_keyboard_grab_window)
1193     {
1194       if (grab_window)
1195         *grab_window = (GdkWindow *)_gdk_fb_keyboard_grab_window;
1196       if (owner_events)
1197         *owner_events = _gdk_fb_keyboard_grab_owner_events;
1198
1199       return TRUE;
1200     }
1201   else
1202     return FALSE;
1203 }
1204
1205
1206 /*
1207  *--------------------------------------------------------------
1208  * gdk_screen_get_width
1209  *
1210  *   Return the width of the screen.
1211  *
1212  * Arguments:
1213  *
1214  * Results:
1215  *
1216  * Side effects:
1217  *
1218  *--------------------------------------------------------------
1219  */
1220
1221 gint
1222 gdk_screen_get_width (GdkScreen *screen)
1223 {
1224   return gdk_display->fb_width;
1225 }
1226
1227 /*
1228  *--------------------------------------------------------------
1229  * gdk_screen_get_height
1230  *
1231  *   Return the height of the screen.
1232  *
1233  * Arguments:
1234  *
1235  * Results:
1236  *
1237  * Side effects:
1238  *
1239  *--------------------------------------------------------------
1240  */
1241
1242 gint
1243 gdk_screen_get_height (GdkScreen *screen)
1244 {
1245   return gdk_display->fb_height;
1246 }
1247
1248 /*
1249  *--------------------------------------------------------------
1250  * gdk_screen_get_width_mm
1251  *
1252  *   Return the width of the screen in millimeters.
1253  *
1254  * Arguments:
1255  *
1256  * Results:
1257  *
1258  * Side effects:
1259  *
1260  *--------------------------------------------------------------
1261  */
1262
1263 gint
1264 gdk_screen_get_width_mm (GdkScreen *screen)
1265 {
1266   return 0.5 + gdk_screen_width () * (25.4 / 72.);
1267 }
1268
1269 /*
1270  *--------------------------------------------------------------
1271  * gdk_screen_get_height_mm
1272  *
1273  *   Return the height of the screen in millimeters.
1274  *
1275  * Arguments:
1276  *
1277  * Results:
1278  *
1279  * Side effects:
1280  *
1281  *--------------------------------------------------------------
1282  */
1283
1284 gint
1285 gdk_screen_get_height_mm (GdkScreen *screen)
1286 {
1287   return 0.5 + gdk_screen_height () * (25.4 / 72.);
1288 }
1289
1290 void
1291 _gdk_windowing_display_set_sm_client_id (GdkDisplay*  display,
1292                                          const gchar* sm_client_id)
1293 {
1294 }
1295
1296 extern void keyboard_shutdown(void);
1297
1298 void
1299 _gdk_windowing_exit (void)
1300 {
1301   struct sigaction action;
1302
1303   /* don't get interrupted while exiting
1304    * (cf. gdkrender-fb.c:gdk_shadow_fb_init) */
1305   action.sa_handler = SIG_IGN;
1306   sigemptyset (&action.sa_mask);
1307   action.sa_flags = 0;
1308
1309   gdk_fb_mouse_close ();
1310   /*leak  g_free (gdk_fb_mouse);*/
1311   
1312   gdk_fb_keyboard_close ();
1313   /*leak g_free (gdk_fb_keyboard);*/
1314   
1315   gdk_fb_display_destroy (gdk_display);
1316   
1317   gdk_display = NULL;
1318 }
1319
1320 gchar *
1321 gdk_get_display(void)
1322 {
1323   gchar *s;
1324
1325   s = getenv ("GDK_DISPLAY");
1326   if (s==0)
1327     s = "/dev/fb0";
1328   
1329   return g_strdup (s);
1330 }
1331
1332 void
1333 gdk_display_beep (GdkDisplay *display)
1334 {
1335   static int pitch = 600, duration = 100;
1336   gulong arg;
1337
1338   /* Thank you XFree86 */
1339   arg = ((1193190 / pitch) & 0xffff) |
1340     (((unsigned long)duration) << 16);
1341
1342   ioctl (gdk_display->tty_fd, KDMKTONE, arg);
1343 }
1344
1345 /* utils */
1346 static const guint type_masks[] = {
1347   GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE          = 0, */
1348   GDK_STRUCTURE_MASK, /* GDK_DESTROY            = 1, */
1349   GDK_EXPOSURE_MASK, /* GDK_EXPOSE              = 2, */
1350   GDK_POINTER_MOTION_MASK, /* GDK_MOTION_NOTIFY = 3, */
1351   GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS    = 4, */
1352   GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS   = 5, */
1353   GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS   = 6, */
1354   GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE        = 7, */
1355   GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS  = 8, */
1356   GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE      = 9, */
1357   GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY    = 10, */
1358   GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY    = 11, */
1359   GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE    = 12, */
1360   GDK_STRUCTURE_MASK, /* GDK_CONFIGURE          = 13, */
1361   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP                = 14, */
1362   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP              = 15, */
1363   GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY      = 16, */
1364   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR      = 17, */
1365   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18, */
1366   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY     = 19, */
1367   GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN    = 20, */
1368   GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT  = 21, */
1369   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER        = 22, */
1370   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE        = 23, */
1371   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION       = 24, */
1372   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS       = 25, */
1373   GDK_ALL_EVENTS_MASK, /* GDK_DROP_START        = 26, */
1374   GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED     = 27, */
1375   GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT      = 28, */
1376   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29, */
1377   GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE           = 30, */
1378   GDK_SCROLL_MASK /* GDK_SCROLL            = 31 */
1379 };
1380
1381 GdkWindow *
1382 gdk_fb_other_event_window (GdkWindow *window,
1383                            GdkEventType type)
1384 {
1385   guint32 evmask;
1386   GdkWindow *w;
1387
1388   w = window;
1389   while (w != _gdk_parent_root)
1390     {
1391       /* Huge hack, so that we don't propagate events to GtkWindow->frame */
1392       if ((w != window) &&
1393           (GDK_WINDOW_P (w)->window_type != GDK_WINDOW_CHILD) &&
1394           (g_object_get_data (G_OBJECT (w), "gdk-window-child-handler")))
1395           break;
1396           
1397       evmask = GDK_WINDOW_OBJECT(window)->event_mask;
1398
1399       if (evmask & type_masks[type])
1400         return w;
1401       
1402       w = gdk_window_get_parent (w);
1403     }
1404   
1405   return NULL;
1406 }
1407
1408 GdkWindow *
1409 gdk_fb_pointer_event_window (GdkWindow *window,
1410                              GdkEventType type)
1411 {
1412   guint evmask;
1413   GdkModifierType mask;
1414   GdkWindow *w;
1415           
1416   gdk_fb_mouse_get_info (NULL, NULL, &mask);
1417   
1418   if (_gdk_fb_pointer_grab_window &&
1419       !_gdk_fb_pointer_grab_owner_events)
1420     {
1421       evmask = _gdk_fb_pointer_grab_events;
1422
1423       if (evmask & (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK))
1424         {
1425           if (((mask & GDK_BUTTON1_MASK) && (evmask & GDK_BUTTON1_MOTION_MASK)) ||
1426               ((mask & GDK_BUTTON2_MASK) && (evmask & GDK_BUTTON2_MOTION_MASK)) ||
1427               ((mask & GDK_BUTTON3_MASK) && (evmask & GDK_BUTTON3_MOTION_MASK)))
1428             evmask |= GDK_POINTER_MOTION_MASK;
1429         }
1430
1431       if (evmask & type_masks[type])
1432         return _gdk_fb_pointer_grab_window;
1433       else
1434         return NULL;
1435     }
1436
1437   w = window;
1438   while (w != _gdk_parent_root)
1439     {
1440       /* Huge hack, so that we don't propagate events to GtkWindow->frame */
1441       if ((w != window) &&
1442           (GDK_WINDOW_P (w)->window_type != GDK_WINDOW_CHILD) &&
1443           (g_object_get_data (G_OBJECT (w), "gdk-window-child-handler")))
1444           break;
1445       
1446       evmask = GDK_WINDOW_OBJECT(window)->event_mask;
1447
1448       if (evmask & (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK))
1449         {
1450           if (((mask & GDK_BUTTON1_MASK) && (evmask & GDK_BUTTON1_MOTION_MASK)) ||
1451               ((mask & GDK_BUTTON2_MASK) && (evmask & GDK_BUTTON2_MOTION_MASK)) ||
1452               ((mask & GDK_BUTTON3_MASK) && (evmask & GDK_BUTTON3_MOTION_MASK)))
1453             evmask |= GDK_POINTER_MOTION_MASK;
1454         }
1455
1456       if (evmask & type_masks[type])
1457         return w;
1458       
1459       w = gdk_window_get_parent (w);
1460     }
1461
1462   if (_gdk_fb_pointer_grab_window &&
1463       _gdk_fb_pointer_grab_owner_events)
1464     {
1465       evmask = _gdk_fb_pointer_grab_events;
1466       
1467       if (evmask & (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK))
1468         {
1469           if (((mask & GDK_BUTTON1_MASK) && (evmask & GDK_BUTTON1_MOTION_MASK)) ||
1470               ((mask & GDK_BUTTON2_MASK) && (evmask & GDK_BUTTON2_MOTION_MASK)) ||
1471               ((mask & GDK_BUTTON3_MASK) && (evmask & GDK_BUTTON3_MOTION_MASK)))
1472             evmask |= GDK_POINTER_MOTION_MASK;
1473         }
1474       
1475       if (evmask & type_masks[type])
1476         return _gdk_fb_pointer_grab_window;
1477     }
1478   
1479   return NULL;
1480 }
1481
1482 GdkWindow *
1483 gdk_fb_keyboard_event_window (GdkWindow *window,
1484                               GdkEventType type)
1485 {
1486   guint32 evmask;
1487   GdkWindow *w;
1488   
1489   if (_gdk_fb_keyboard_grab_window &&
1490       !_gdk_fb_keyboard_grab_owner_events)
1491     {
1492       return _gdk_fb_keyboard_grab_window;
1493     }
1494   
1495   w = window;
1496   while (w != _gdk_parent_root)
1497     {
1498       /* Huge hack, so that we don't propagate events to GtkWindow->frame */
1499       if ((w != window) &&
1500           (GDK_WINDOW_P (w)->window_type != GDK_WINDOW_CHILD) &&
1501           (g_object_get_data (G_OBJECT (w), "gdk-window-child-handler")))
1502           break;
1503           
1504       evmask = GDK_WINDOW_OBJECT(window)->event_mask;
1505
1506       if (evmask & type_masks[type])
1507         return w;
1508       
1509       w = gdk_window_get_parent (w);
1510     }
1511   
1512   if (_gdk_fb_keyboard_grab_window &&
1513       _gdk_fb_keyboard_grab_owner_events)
1514     {
1515       return _gdk_fb_keyboard_grab_window;
1516     }
1517
1518   return NULL;
1519 }
1520
1521 GdkEvent *
1522 gdk_event_make (GdkWindow *window,
1523                 GdkEventType type,
1524                 gboolean append_to_queue)
1525 {
1526   GdkEvent *event = gdk_event_new (type);
1527   guint32 the_time;
1528   
1529   the_time = gdk_fb_get_time ();
1530   
1531   event->any.window = gdk_window_ref (window);
1532   event->any.send_event = FALSE;
1533   switch (type)
1534     {
1535     case GDK_MOTION_NOTIFY:
1536       event->motion.time = the_time;
1537       event->motion.axes = NULL;
1538       break;
1539     case GDK_BUTTON_PRESS:
1540     case GDK_2BUTTON_PRESS:
1541     case GDK_3BUTTON_PRESS:
1542     case GDK_BUTTON_RELEASE:
1543       event->button.time = the_time;
1544       event->button.axes = NULL;
1545       break;
1546     case GDK_KEY_PRESS:
1547     case GDK_KEY_RELEASE:
1548       event->key.time = the_time;
1549       break;
1550     case GDK_ENTER_NOTIFY:
1551     case GDK_LEAVE_NOTIFY:
1552       event->crossing.time = the_time;
1553       break;
1554       
1555     case GDK_PROPERTY_NOTIFY:
1556       event->property.time = the_time;
1557       break;
1558       
1559     case GDK_SELECTION_CLEAR:
1560     case GDK_SELECTION_REQUEST:
1561     case GDK_SELECTION_NOTIFY:
1562       event->selection.time = the_time;
1563       break;
1564     case GDK_PROXIMITY_IN:
1565     case GDK_PROXIMITY_OUT:
1566       event->proximity.time = the_time;
1567       break;
1568     case GDK_DRAG_ENTER:
1569     case GDK_DRAG_LEAVE:
1570     case GDK_DRAG_MOTION:
1571     case GDK_DRAG_STATUS:
1572     case GDK_DROP_START:
1573     case GDK_DROP_FINISHED:
1574       event->dnd.time = the_time;
1575       break;
1576       
1577     case GDK_FOCUS_CHANGE:
1578     case GDK_CONFIGURE:
1579     case GDK_MAP:
1580     case GDK_UNMAP:
1581     case GDK_CLIENT_EVENT:
1582     case GDK_VISIBILITY_NOTIFY:
1583     case GDK_NO_EXPOSE:
1584     case GDK_SCROLL:
1585     case GDK_DELETE:
1586     case GDK_DESTROY:
1587     case GDK_EXPOSE:
1588     default:
1589       break;
1590     }
1591   
1592   if (append_to_queue)
1593     _gdk_event_queue_append (gdk_display_get_default (), event);
1594   
1595   return event;
1596 }
1597
1598 void
1599 gdk_fb_set_rotation (GdkFBAngle angle)
1600 {
1601   if (angle == _gdk_fb_screen_angle)
1602     return;
1603   
1604 #ifdef ENABLE_SHADOW_FB
1605   if (gdk_display)
1606     {
1607       gdk_shadow_fb_stop_updates ();
1608
1609       gdk_fb_cursor_hide ();
1610       
1611       _gdk_fb_screen_angle = angle;
1612
1613       if (angle % 2 == 0)
1614         {
1615           gdk_display->fb_width = gdk_display->modeinfo.xres;
1616           gdk_display->fb_height = gdk_display->modeinfo.yres;
1617         } 
1618       else
1619         {
1620           gdk_display->fb_width = gdk_display->modeinfo.yres;
1621           gdk_display->fb_height = gdk_display->modeinfo.xres;
1622         }
1623       gdk_display->fb_stride =
1624         gdk_display->fb_width * (gdk_display->modeinfo.bits_per_pixel / 8);
1625       
1626       gdk_fb_recompute_all();
1627       gdk_fb_redraw_all ();
1628       
1629       gdk_fb_cursor_unhide ();
1630     }
1631   else
1632     _gdk_fb_screen_angle = angle;
1633 #else
1634   g_warning ("Screen rotation without shadow fb not supported.");
1635 #endif
1636 }
1637
1638 void
1639 gdk_error_trap_push (void)
1640 {
1641 }
1642
1643 gint
1644 gdk_error_trap_pop (void)
1645 {
1646   return 0;
1647 }
1648
1649 void
1650 gdk_notify_startup_complete (void)
1651 {
1652 }