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