Annotation of tme/host/gtk/gtk-screen.c, revision 1.1.1.4

1.1.1.4 ! root        1: /* $Id: gtk-screen.c,v 1.11 2009/08/30 21:39:03 fredette Exp $ */
1.1       root        2: 
                      3: /* host/gtk/gtk-screen.c - GTK screen support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
1.1.1.4 ! root       37: _TME_RCSID("$Id: gtk-screen.c,v 1.11 2009/08/30 21:39:03 fredette Exp $");
1.1       root       38: 
                     39: /* we are aware of the problems with gdk_image_new_bitmap, and we cope
                     40:    with them, so we define GDK_ENABLE_BROKEN to get its prototype
                     41:    under GTK 2: */
                     42: #define GDK_ENABLE_BROKEN
                     43: 
                     44: /* includes: */
                     45: #include "gtk-display.h"
                     46: #include <stdlib.h>
                     47: 
                     48: /* macros: */
                     49: 
                     50: /* the GTK 1.x gtk_image_new function is the GTK 2.x
                     51:    gtk_image_new_from_image function: */
                     52: #if GTK_MAJOR_VERSION == 1
                     53: #define gtk_image_new_from_image gtk_image_new
                     54: #endif /* GTK_MAJOR_VERSION == 1 */
                     55: 
                     56: /* the GTK screens update thread: */
                     57: void
                     58: _tme_gtk_screen_th_update(struct tme_gtk_display *display)
                     59: {
                     60:   struct tme_gtk_screen *screen;
                     61:   struct tme_fb_connection *conn_fb_other;
                     62:   int changed;
                     63:   int rc;
                     64:   
                     65:   /* loop forever: */
                     66:   for (;;) {
                     67: 
                     68:     /* lock the mutex: */
                     69:     tme_mutex_lock(&display->tme_gtk_display_mutex);
                     70: 
                     71:     /* loop over all screens: */
                     72:     for (screen = display->tme_gtk_display_screens;
                     73:         screen != NULL;
                     74:         screen = screen->tme_gtk_screen_next) {
                     75: 
                     76:       /* skip this screen if it's unconnected: */
                     77:       if (screen->tme_gtk_screen_fb == NULL) {
                     78:        continue;
                     79:       }
                     80: 
                     81:       /* get the other side of this connection: */
                     82:       conn_fb_other
                     83:        = ((struct tme_fb_connection *) 
                     84:           screen->tme_gtk_screen_fb->tme_fb_connection.tme_connection_other);
                     85: 
                     86:       /* if the framebuffer has an update function, call it: */
                     87:       if (conn_fb_other->tme_fb_connection_update != NULL) {
                     88:        rc = (*conn_fb_other->tme_fb_connection_update)(conn_fb_other);
                     89:        assert (rc == TME_OK);
                     90:       }
                     91: 
1.1.1.4 ! root       92:       /* if this framebuffer needs a full redraw: */
        !            93:       if (screen->tme_gtk_screen_full_redraw) {
        !            94: 
        !            95:        /* force the next translation to retranslate the entire buffer: */
        !            96:        tme_fb_xlat_redraw(conn_fb_other);
        !            97:        conn_fb_other->tme_fb_connection_offset_updated_first = 0;
        !            98:        conn_fb_other->tme_fb_connection_offset_updated_last = 0 - (tme_uint32_t) 1;
        !            99: 
        !           100:        /* clear the full redraw flag: */
        !           101:        screen->tme_gtk_screen_full_redraw = FALSE;
        !           102:       }
        !           103: 
1.1       root      104:       /* translate this framebuffer's contents: */
                    105:       changed = (*screen->tme_gtk_screen_fb_xlat)
                    106:        (((struct tme_fb_connection *) 
                    107:          screen->tme_gtk_screen_fb->tme_fb_connection.tme_connection_other),
                    108:         screen->tme_gtk_screen_fb);
                    109: 
                    110:       /* if those contents changed, redraw the widget: */
                    111:       if (changed) {
                    112:        gtk_widget_queue_draw(screen->tme_gtk_screen_gtkimage);
                    113:       }
                    114:     }
                    115: 
                    116:     /* unlock the mutex: */
                    117:     tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    118: 
                    119:     /* update again in .5 seconds: */
                    120:     tme_thread_sleep_yield(0, 500000);
                    121:   }
                    122:   /* NOTREACHED */
                    123: }
                    124: 
                    125: /* this recovers the bits-per-pixel value for a GdkImage: */
                    126: static unsigned int
                    127: _tme_gtk_gdkimage_bipp(GdkImage *image)
                    128: {
1.1.1.2   root      129:   unsigned int bipp, total_bits;
1.1       root      130: 
1.1.1.2   root      131:   /* if the bytes per pixel value is greater than one, or if the image
                    132:      depth is 8 or greater, just convert the bytes per pixel value to
                    133:      bits per pixel: */
                    134:   if (image->bpp > 1
                    135:       || image->depth >= 8) {
                    136:     return (image->bpp * 8);
                    137:   }
                    138: 
                    139:   /* otherwise, we know that the depth of the image is less than
                    140:      eight, and the number of bits per pixel is eight or less: */
                    141:   total_bits = image->bpl;
                    142:   total_bits *= 8;
                    143:   for (bipp = 8;
                    144:        bipp > image->depth && (bipp * image->width) > total_bits;
                    145:        bipp >>= 1);
1.1       root      146:   return (bipp);
                    147: }
                    148: 
                    149: /* this recovers the scanline-pad value for a GdkImage: */
                    150: static unsigned int
                    151: _tme_gtk_gdkimage_scanline_pad(GdkImage *image)
                    152: {
                    153: 
                    154:   if ((image->bpl % sizeof(tme_uint32_t)) == 0) {
                    155:     return (32);
                    156:   }
                    157:   if ((image->bpl % sizeof(tme_uint16_t)) == 0) {
                    158:     return (16);
                    159:   }
1.1.1.3   root      160:   return (8);
1.1       root      161: }
                    162: 
                    163: /* this is called for a mode change: */
                    164: int
                    165: _tme_gtk_screen_mode_change(struct tme_fb_connection *conn_fb)
                    166: {
                    167:   struct tme_gtk_display *display;
                    168:   struct tme_gtk_screen *screen;
                    169:   struct tme_fb_connection *conn_fb_other;
                    170:   struct tme_fb_xlat fb_xlat_q;
                    171:   const struct tme_fb_xlat *fb_xlat_a;
                    172:   int scale;
                    173:   unsigned long fb_area, avail_area, percentage;
                    174:   gint width, height;
1.1.1.3   root      175:   gint height_extra;
                    176:   const void *map_g_old;
                    177:   const void *map_r_old;
                    178:   const void *map_b_old;
                    179:   const tme_uint32_t *map_pixel_old;
                    180:   tme_uint32_t map_pixel_count_old;  
                    181:   tme_uint32_t colorset;
1.1       root      182:   GdkImage *gdkimage;
                    183:   GdkVisual *visual;
1.1.1.2   root      184:   tme_uint32_t color_count, color_i;
1.1.1.3   root      185:   tme_uint32_t color_count_distinct;
                    186:   tme_uint32_t color_j;
1.1.1.2   root      187:   struct tme_fb_color *colors_tme;
                    188:   GdkColor *colors_gdk;
                    189:   gboolean *success;
                    190:   gboolean warned_color_alloc;
1.1       root      191: 
                    192:   /* recover our data structures: */
                    193:   display = conn_fb->tme_fb_connection.tme_connection_element->tme_element_private;
                    194:   conn_fb_other = (struct tme_fb_connection *) conn_fb->tme_fb_connection.tme_connection_other;
                    195: 
                    196:   /* lock our mutex: */
                    197:   tme_mutex_lock(&display->tme_gtk_display_mutex);
                    198: 
                    199:   /* find the screen that this framebuffer connection references: */
                    200:   for (screen = display->tme_gtk_display_screens;
                    201:        (screen != NULL
                    202:        && screen->tme_gtk_screen_fb != conn_fb);
                    203:        screen = screen->tme_gtk_screen_next);
                    204:   assert (screen != NULL);
                    205: 
                    206:   /* if the user hasn't specified a scaling, pick one: */
                    207:   scale = screen->tme_gtk_screen_fb_scale;
                    208:   if (scale < 0) {
                    209: 
                    210:     /* calulate the areas, in square pixels, of the emulated
                    211:        framebuffer and the host's screen: */
                    212:     fb_area = (conn_fb_other->tme_fb_connection_width
                    213:               * conn_fb_other->tme_fb_connection_height);
                    214:     avail_area = (gdk_screen_width()
                    215:                  * gdk_screen_height());
                    216: 
                    217:     /* see what percentage of the host's screen would be taken up by
                    218:        an unscaled emulated framebuffer: */
                    219:     percentage = (fb_area * 100) / avail_area;
                    220: 
                    221:     /* if this is at least 70%, halve the emulated framebuffer, else
                    222:        if this is 30% or less, double the emulated framebuffer: */
                    223:     if (percentage >= 70) {
                    224:       scale = TME_FB_XLAT_SCALE_HALF;
                    225:     }
                    226:     else if (percentage <= 30) {
                    227:       scale = TME_FB_XLAT_SCALE_DOUBLE;
                    228:     }
                    229:     else {
                    230:       scale = TME_FB_XLAT_SCALE_NONE;
                    231:     }
                    232: 
                    233:     screen->tme_gtk_screen_fb_scale = -scale;
                    234:   }
                    235: 
                    236:   /* get the system's default visual: */
                    237:   visual = gdk_visual_get_system();
                    238: 
1.1.1.3   root      239:   /* get the required dimensions for the GdkImage: */
1.1       root      240:   width = ((conn_fb_other->tme_fb_connection_width
                    241:            * scale)
                    242:           / TME_FB_XLAT_SCALE_NONE);
                    243:   height = ((conn_fb_other->tme_fb_connection_height
                    244:             * scale)
                    245:            / TME_FB_XLAT_SCALE_NONE);
1.1.1.3   root      246:   /* NB: we need to allocate an extra scanline's worth (or, if we're
                    247:      doubling, an extra two scanlines' worth) of image, because the
                    248:      framebuffer translation functions can sometimes overtranslate
                    249:      (see the explanation of TME_FB_XLAT_RUN in fb-xlat-auto.sh): */
                    250:   height_extra
                    251:     = (scale == TME_FB_XLAT_SCALE_DOUBLE
                    252:        ? 2
                    253:        : 1);
                    254: 
                    255:   /* if the previous gdkimage isn't the right size: */
                    256:   gdkimage = screen->tme_gtk_screen_gdkimage;
                    257:   if (gdkimage->width != width
                    258:       || gdkimage->height != (height + height_extra)) {
                    259: 
                    260:     /* allocate a new gdkimage: */
                    261:     gdkimage = gdk_image_new(GDK_IMAGE_FASTEST,
                    262:                             visual,
                    263:                             width,
                    264:                             height
                    265:                             + height_extra);
                    266: 
                    267:     /* set the new image on the image widget: */
                    268:     gtk_image_set(GTK_IMAGE(screen->tme_gtk_screen_gtkimage),
                    269:                  gdkimage,
                    270:                  NULL);
                    271: 
                    272:     /* destroy the previous gdkimage and remember the new one: */
                    273:     gdk_image_destroy(screen->tme_gtk_screen_gdkimage);
                    274:     screen->tme_gtk_screen_gdkimage = gdkimage;
                    275:   }
                    276: 
                    277:   /* remember all previously allocated maps and colors, but otherwise
                    278:      remove them from our framebuffer structure: */
                    279:   map_g_old = conn_fb->tme_fb_connection_map_g;
                    280:   map_r_old = conn_fb->tme_fb_connection_map_r;
                    281:   map_b_old = conn_fb->tme_fb_connection_map_b;
                    282:   map_pixel_old = conn_fb->tme_fb_connection_map_pixel;
                    283:   map_pixel_count_old = conn_fb->tme_fb_connection_map_pixel_count;
1.1.1.2   root      284:   conn_fb->tme_fb_connection_map_g = NULL;
                    285:   conn_fb->tme_fb_connection_map_r = NULL;
                    286:   conn_fb->tme_fb_connection_map_b = NULL;
                    287:   conn_fb->tme_fb_connection_map_pixel = NULL;
                    288:   conn_fb->tme_fb_connection_map_pixel_count = 0;
                    289: 
1.1       root      290:   /* update our framebuffer connection: */
                    291:   conn_fb->tme_fb_connection_width = width;
                    292:   conn_fb->tme_fb_connection_height = height;
                    293:   conn_fb->tme_fb_connection_depth = gdkimage->depth;
                    294:   conn_fb->tme_fb_connection_bits_per_pixel = _tme_gtk_gdkimage_bipp(gdkimage);
                    295:   conn_fb->tme_fb_connection_skipx = 0;
                    296:   conn_fb->tme_fb_connection_scanline_pad = _tme_gtk_gdkimage_scanline_pad(gdkimage);
                    297:   conn_fb->tme_fb_connection_order = (gdkimage->byte_order == GDK_LSB_FIRST
                    298:                                      ? TME_ENDIAN_LITTLE
                    299:                                      : TME_ENDIAN_BIG);
                    300:   conn_fb->tme_fb_connection_buffer = gdkimage->mem;
1.1.1.2   root      301:   switch (visual->type) {
                    302:   case GDK_VISUAL_STATIC_GRAY: 
                    303:   case GDK_VISUAL_GRAYSCALE:
                    304:     conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_MONOCHROME;
                    305:     break;
                    306:   default:
                    307:     assert(FALSE);
                    308:     /* FALLTHROUGH */
                    309:   case GDK_VISUAL_STATIC_COLOR:
                    310:   case GDK_VISUAL_PSEUDO_COLOR:
                    311:   case GDK_VISUAL_DIRECT_COLOR:
                    312:   case GDK_VISUAL_TRUE_COLOR:
                    313:     conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_COLOR;
                    314:     break;
                    315:   }
                    316:   switch (visual->type) {
                    317:   case GDK_VISUAL_DIRECT_COLOR:
                    318:     /* we set the primary maps to anything non-NULL, to indicate that
                    319:        primaries are index mapped: */
                    320:     conn_fb->tme_fb_connection_map_g = conn_fb;
                    321:     conn_fb->tme_fb_connection_map_r = conn_fb;
                    322:     conn_fb->tme_fb_connection_map_b = conn_fb;
                    323:     /* FALLTHROUGH */
                    324:   case GDK_VISUAL_TRUE_COLOR:
                    325:     conn_fb->tme_fb_connection_mask_g = visual->green_mask;
                    326:     conn_fb->tme_fb_connection_mask_r = visual->red_mask;
                    327:     conn_fb->tme_fb_connection_mask_b = visual->blue_mask;
                    328:     break;
                    329:   default:
                    330:     conn_fb->tme_fb_connection_mask_g = 0;
                    331:     conn_fb->tme_fb_connection_mask_r = 0;
                    332:     conn_fb->tme_fb_connection_mask_b = 0;
                    333:     break;
                    334:   }
1.1       root      335: 
1.1.1.2   root      336:   /* get the needed colors: */
1.1.1.3   root      337:   colorset = tme_fb_xlat_colors_get(conn_fb_other, scale, conn_fb, &colors_tme);
                    338:   color_count = conn_fb->tme_fb_connection_map_pixel_count;
                    339: 
                    340:   /* if we need to allocate colors, but the colorset is not tied to
                    341:      the source framebuffer characteristics, and is identical to the
                    342:      currently allocated colorset, we can reuse the previously
                    343:      allocated maps and colors: */
                    344:   if (color_count > 0
                    345:       && colorset != TME_FB_COLORSET_NONE
                    346:       && colorset == screen->tme_gtk_screen_colorset) {
                    347: 
                    348:     /* free the requested color array: */
                    349:     tme_free(colors_tme);
                    350: 
                    351:     /* restore the previously allocated maps and colors: */
                    352:     conn_fb->tme_fb_connection_map_g = map_g_old;
                    353:     conn_fb->tme_fb_connection_map_r = map_r_old;
                    354:     conn_fb->tme_fb_connection_map_b = map_b_old;
                    355:     conn_fb->tme_fb_connection_map_pixel = map_pixel_old;
                    356:     conn_fb->tme_fb_connection_map_pixel_count = map_pixel_count_old;
                    357:   }
                    358: 
                    359:   /* otherwise, we may need to free and/or allocate colors: */
                    360:   else {
                    361: 
                    362:     /* save the colorset signature: */
                    363:     screen->tme_gtk_screen_colorset = colorset;
                    364: 
                    365:     /* free any previously allocated maps and colors: */
                    366:     if (map_g_old != NULL) {
                    367:       tme_free((void *) map_g_old);
                    368:     }
                    369:     if (map_r_old != NULL) {
                    370:       tme_free((void *) map_r_old);
                    371:     }
                    372:     if (map_b_old != NULL) {
                    373:       tme_free((void *) map_b_old);
                    374:     }
                    375:     if (map_pixel_old != NULL) {
                    376: 
                    377:       /* recreate the array of GdkColor: */
                    378:       colors_gdk = tme_new(GdkColor, map_pixel_count_old);
                    379:       color_i = 0;
                    380:       do {
                    381:        colors_gdk[color_i].pixel = map_pixel_old[color_i];
                    382:       } while (++color_i < map_pixel_count_old);
                    383: 
                    384:       /* free the colors: */
                    385:       gdk_colormap_free_colors(gdk_colormap_get_system(),
                    386:                               colors_gdk,
                    387:                               map_pixel_count_old);
                    388:       tme_free(colors_gdk);
                    389:       tme_free((void *) map_pixel_old);
                    390:     }
                    391: 
                    392:     /* if we need to allocate colors: */
                    393:     if (color_count > 0) {
                    394: 
                    395:       /* make the GdkColor array, and count the number of distinct colors: */
                    396:       colors_gdk = tme_new(GdkColor, color_count * 2);
                    397:       color_count_distinct = 0;
                    398:       for (color_i = 0; color_i < color_count; color_i++) {
                    399:        color_j = colors_tme[color_i].tme_fb_color_pixel;
                    400:        colors_gdk[color_j].green = colors_tme[color_i].tme_fb_color_value_g;
                    401:        colors_gdk[color_j].red   = colors_tme[color_i].tme_fb_color_value_r;
                    402:        colors_gdk[color_j].blue  = colors_tme[color_i].tme_fb_color_value_b;
                    403:        if (color_j >= color_count_distinct) {
                    404:          color_count_distinct = color_j + 1;
                    405:        }
                    406:       }
                    407:       success = tme_new(gboolean, color_count_distinct);
                    408: 
                    409:       /* allocate exact matches for as many colors as possible: */
                    410:       gdk_colormap_alloc_colors(gdk_colormap_get_system(),
                    411:                                colors_gdk,
                    412:                                color_count_distinct,
                    413:                                FALSE,
                    414:                                FALSE,
                    415:                                success);
                    416: 
                    417:       /* allocate read-only best matches for any colors we failed to
                    418:         allocate exactly: */
                    419:       warned_color_alloc = FALSE;
                    420:       for (color_i = 0; color_i < color_count; color_i++) {
                    421:        color_j = colors_tme[color_i].tme_fb_color_pixel;
                    422:        if (!success[color_j]) {
                    423:          if (!gdk_colormap_alloc_color(gdk_colormap_get_system(),
                    424:                                        &colors_gdk[color_j],
                    425:                                        FALSE,
                    426:                                        TRUE)) {
                    427:            if (!warned_color_alloc) {
                    428:              warned_color_alloc = TRUE;
                    429:              tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOMEM,
                    430:                      (&display->tme_gtk_display_element->tme_element_log_handle,
                    431:                       _("could not allocate all colors")));
                    432:            }
1.1.1.2   root      433:          }
                    434:        }
1.1.1.3   root      435:        colors_tme[color_i].tme_fb_color_pixel = colors_gdk[color_j].pixel;
1.1.1.2   root      436:       }
1.1.1.3   root      437: 
                    438:       /* free the arrays used with gdk_colormap_alloc_colors(): */
                    439:       tme_free(success);
                    440:       tme_free(colors_gdk);
                    441: 
                    442:       /* set the needed colors: */
                    443:       tme_fb_xlat_colors_set(conn_fb_other, scale, conn_fb, colors_tme);
1.1       root      444:     }
                    445:   }
                    446: 
                    447:   /* compose the framebuffer translation question: */
                    448:   fb_xlat_q.tme_fb_xlat_width                  = conn_fb_other->tme_fb_connection_width;
                    449:   fb_xlat_q.tme_fb_xlat_height                 = conn_fb_other->tme_fb_connection_height;
                    450:   fb_xlat_q.tme_fb_xlat_scale                  = (unsigned int) scale;
                    451:   fb_xlat_q.tme_fb_xlat_src_depth              = conn_fb_other->tme_fb_connection_depth;
                    452:   fb_xlat_q.tme_fb_xlat_src_bits_per_pixel     = conn_fb_other->tme_fb_connection_bits_per_pixel;
                    453:   fb_xlat_q.tme_fb_xlat_src_skipx              = conn_fb_other->tme_fb_connection_skipx;
                    454:   fb_xlat_q.tme_fb_xlat_src_scanline_pad       = conn_fb_other->tme_fb_connection_scanline_pad;
                    455:   fb_xlat_q.tme_fb_xlat_src_order              = conn_fb_other->tme_fb_connection_order;
1.1.1.2   root      456:   fb_xlat_q.tme_fb_xlat_src_class              = conn_fb_other->tme_fb_connection_class;
                    457:   fb_xlat_q.tme_fb_xlat_src_map                        = (conn_fb_other->tme_fb_connection_map_g != NULL
                    458:                                                   ? TME_FB_XLAT_MAP_INDEX
                    459:                                                   : TME_FB_XLAT_MAP_LINEAR);
                    460:   fb_xlat_q.tme_fb_xlat_src_map_bits           = conn_fb_other->tme_fb_connection_map_bits;
                    461:   fb_xlat_q.tme_fb_xlat_src_mask_g             = conn_fb_other->tme_fb_connection_mask_g;
                    462:   fb_xlat_q.tme_fb_xlat_src_mask_r             = conn_fb_other->tme_fb_connection_mask_r;
                    463:   fb_xlat_q.tme_fb_xlat_src_mask_b             = conn_fb_other->tme_fb_connection_mask_b;
1.1       root      464:   fb_xlat_q.tme_fb_xlat_dst_depth              = conn_fb->tme_fb_connection_depth;
                    465:   fb_xlat_q.tme_fb_xlat_dst_bits_per_pixel     = conn_fb->tme_fb_connection_bits_per_pixel;
                    466:   fb_xlat_q.tme_fb_xlat_dst_skipx              = conn_fb->tme_fb_connection_skipx;
                    467:   fb_xlat_q.tme_fb_xlat_dst_scanline_pad       = conn_fb->tme_fb_connection_scanline_pad;
                    468:   fb_xlat_q.tme_fb_xlat_dst_order              = conn_fb->tme_fb_connection_order;
1.1.1.2   root      469:   fb_xlat_q.tme_fb_xlat_dst_map                        = (conn_fb->tme_fb_connection_map_g != NULL
                    470:                                                   ? TME_FB_XLAT_MAP_INDEX
                    471:                                                   : TME_FB_XLAT_MAP_LINEAR);
                    472:   fb_xlat_q.tme_fb_xlat_dst_mask_g             = conn_fb->tme_fb_connection_mask_g;
                    473:   fb_xlat_q.tme_fb_xlat_dst_mask_r             = conn_fb->tme_fb_connection_mask_r;
                    474:   fb_xlat_q.tme_fb_xlat_dst_mask_b             = conn_fb->tme_fb_connection_mask_b;
1.1       root      475: 
                    476:   /* ask the framebuffer translation question: */
                    477:   fb_xlat_a = tme_fb_xlat_best(&fb_xlat_q);
                    478: 
                    479:   /* if this translation isn't optimal, log a note: */
                    480:   if (!tme_fb_xlat_is_optimal(fb_xlat_a)) {
                    481:     tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, TME_OK,
                    482:            (&display->tme_gtk_display_element->tme_element_log_handle,
                    483:             _("no optimal framebuffer translation function available")));
                    484:   }
                    485: 
                    486:   /* save the translation function: */
                    487:   screen->tme_gtk_screen_fb_xlat = fb_xlat_a->tme_fb_xlat_func;
                    488: 
                    489:   /* force the next translation to do a complete redraw: */
1.1.1.4 ! root      490:   screen->tme_gtk_screen_full_redraw = TRUE;
1.1       root      491: 
                    492:   /* unlock our mutex: */
                    493:   tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    494: 
                    495:   /* done: */
                    496:   return (TME_OK);
                    497: }
                    498: 
                    499: /* this sets the screen size: */
                    500: static void
                    501: _tme_gtk_screen_scale_set(GtkWidget *widget,
                    502:                          struct tme_gtk_screen *screen,
                    503:                          int scale_new)
                    504: {
                    505:   struct tme_gtk_display *display;
                    506:   int scale_old;
                    507:   int rc;
                    508: 
                    509:   /* return now if the menu item isn't active: */
                    510:   if (!GTK_CHECK_MENU_ITEM(GTK_MENU_ITEM(widget))->active) {
                    511:     return;
                    512:   }
                    513: 
                    514:   /* get the display: */
                    515:   display = screen->tme_gtk_screen_display;
                    516: 
                    517:   /* lock our mutex: */
                    518:   tme_mutex_lock(&display->tme_gtk_display_mutex);
                    519: 
                    520:   /* get the old scaling and set the new scaling: */
                    521:   scale_old = screen->tme_gtk_screen_fb_scale;
                    522:   if (scale_old < 0
                    523:       && scale_new < 0) {
                    524:     scale_new = scale_old;
                    525:   }
                    526:   screen->tme_gtk_screen_fb_scale = scale_new;
                    527: 
                    528:   /* unlock our mutex: */
                    529:   tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    530: 
                    531:   /* call the mode change function if the scaling has changed: */
                    532:   if (scale_new != scale_old) {
                    533:     rc = _tme_gtk_screen_mode_change(screen->tme_gtk_screen_fb);
                    534:     assert (rc == TME_OK);
                    535:   }
                    536: }
                    537: 
                    538: /* this sets the screen scaling to default: */
                    539: static void
                    540: _tme_gtk_screen_scale_default(GtkWidget *widget,
                    541:                              struct tme_gtk_screen *screen)
                    542: {
                    543:   _tme_gtk_screen_scale_set(widget,
                    544:                            screen,
                    545:                            -TME_FB_XLAT_SCALE_NONE);
                    546: }
                    547: 
                    548: /* this sets the screen scaling to half: */
                    549: static void
                    550: _tme_gtk_screen_scale_half(GtkWidget *widget,
                    551:                           struct tme_gtk_screen *screen)
                    552: {
                    553:   _tme_gtk_screen_scale_set(widget,
                    554:                            screen,
                    555:                            TME_FB_XLAT_SCALE_HALF);
                    556: }
                    557: 
                    558: /* this sets the screen scaling to none: */
                    559: static void
                    560: _tme_gtk_screen_scale_none(GtkWidget *widget,
                    561:                           struct tme_gtk_screen *screen)
                    562: {
                    563:   _tme_gtk_screen_scale_set(widget,
                    564:                            screen,
                    565:                            TME_FB_XLAT_SCALE_NONE);
                    566: }
                    567: 
                    568: /* this sets the screen scaling to double: */
                    569: static void
                    570: _tme_gtk_screen_scale_double(GtkWidget *widget,
                    571:                             struct tme_gtk_screen *screen)
                    572: {
                    573:   _tme_gtk_screen_scale_set(widget,
                    574:                            screen,
                    575:                            TME_FB_XLAT_SCALE_DOUBLE);
                    576: }
                    577: 
1.1.1.3   root      578: /* this creates the Screen scaling submenu: */
                    579: static GtkSignalFunc
                    580: _tme_gtk_screen_submenu_scaling(void *_screen,
                    581:                                struct tme_gtk_display_menu_item *menu_item)
                    582: {
                    583:   struct tme_gtk_screen *screen;
                    584: 
                    585:   screen = (struct tme_gtk_screen *) _screen;
                    586:   menu_item->tme_gtk_display_menu_item_widget = NULL;
                    587:   switch (menu_item->tme_gtk_display_menu_item_which) {
                    588:   case 0:
                    589:     menu_item->tme_gtk_display_menu_item_string = _("Default");
                    590:     menu_item->tme_gtk_display_menu_item_widget = &screen->tme_gtk_screen_scale_default;
                    591:     return (GTK_SIGNAL_FUNC(_tme_gtk_screen_scale_default));
                    592:   case 1:
                    593:     menu_item->tme_gtk_display_menu_item_string = _("Half");
                    594:     menu_item->tme_gtk_display_menu_item_widget = &screen->tme_gtk_screen_scale_half;
                    595:     return (GTK_SIGNAL_FUNC(_tme_gtk_screen_scale_half));
                    596:   case 2:
                    597:     menu_item->tme_gtk_display_menu_item_string = _("Full");
                    598:     return (GTK_SIGNAL_FUNC(_tme_gtk_screen_scale_none));
                    599:   case 3:
                    600:     menu_item->tme_gtk_display_menu_item_string = _("Double");
                    601:     return (GTK_SIGNAL_FUNC(_tme_gtk_screen_scale_double));
                    602:   default:
                    603:     break;
                    604:   }
                    605:   return (NULL);
                    606: }
                    607: 
1.1       root      608: /* this makes a new screen: */
                    609: struct tme_gtk_screen *
                    610: _tme_gtk_screen_new(struct tme_gtk_display *display)
                    611: {
                    612:   struct tme_gtk_screen *screen, **_prev;
                    613:   GtkWidget *menu_bar;
                    614:   GtkWidget *menu;
                    615:   GtkWidget *submenu;
                    616:   GtkWidget *menu_item;
                    617:   tme_uint8_t *bitmap_data;
                    618:   unsigned int y;
                    619: #define BLANK_SIDE (16 * 8)
                    620: 
                    621:   /* create the new screen and link it in: */
                    622:   for (_prev = &display->tme_gtk_display_screens;
                    623:        (screen = *_prev) != NULL;
                    624:        _prev = &screen->tme_gtk_screen_next);
                    625:   screen = *_prev = tme_new0(struct tme_gtk_screen, 1);
                    626: 
                    627:   /* the backpointer to the display: */
                    628:   screen->tme_gtk_screen_display = display;
                    629:   
                    630:   /* there is no framebuffer connection yet: */
                    631:   screen->tme_gtk_screen_fb = NULL;
                    632: 
                    633:   /* the user hasn't specified a scaling yet: */
                    634:   screen->tme_gtk_screen_fb_scale
                    635:     = -TME_FB_XLAT_SCALE_NONE;
                    636: 
1.1.1.3   root      637:   /* we have no colorset: */
                    638:   screen->tme_gtk_screen_colorset = TME_FB_COLORSET_NONE;
                    639: 
1.1       root      640:   /* create the top-level window, and allow it to shrink, grow,
                    641:      and auto-shrink: */
                    642:   screen->tme_gtk_screen_window
                    643:     = gtk_window_new(GTK_WINDOW_TOPLEVEL);
                    644:   gtk_window_set_policy(GTK_WINDOW(screen->tme_gtk_screen_window),
1.1.1.4 ! root      645:                        FALSE, FALSE, TRUE);
1.1       root      646: 
                    647:   /* create the outer vertical packing box: */
                    648:   screen->tme_gtk_screen_vbox0
                    649:     = gtk_vbox_new(FALSE, 0);
                    650: 
                    651:   /* add the outer vertical packing box to the window: */
                    652:   gtk_container_add(GTK_CONTAINER(screen->tme_gtk_screen_window),
                    653:                    screen->tme_gtk_screen_vbox0);
                    654: 
                    655:   /* create the menu bar and pack it into the outer vertical packing
                    656:      box: */
                    657:   menu_bar = gtk_menu_bar_new ();
                    658:   gtk_box_pack_start(GTK_BOX(screen->tme_gtk_screen_vbox0), 
                    659:                     menu_bar,
                    660:                     FALSE, FALSE, 0);
                    661:   gtk_widget_show(menu_bar);
                    662: 
                    663:   /* create the Screen menu: */
                    664:   menu = gtk_menu_new();
                    665: 
                    666:   /* create the Screen scaling submenu: */
1.1.1.3   root      667:   submenu
                    668:     = _tme_gtk_display_menu_radio(screen,
                    669:                                  _tme_gtk_screen_submenu_scaling);
1.1       root      670: 
                    671:   /* create the Screen scaling submenu item: */
                    672:   menu_item = gtk_menu_item_new_with_label(_("Scale"));
                    673:   gtk_widget_show(menu_item);
                    674:   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
                    675:   gtk_menu_append(GTK_MENU(menu), menu_item);
                    676: 
                    677:   /* create the Screen menu bar item, attach the menu to it, and 
                    678:      attach the menu bar item to the menu bar: */
                    679:   menu_item = gtk_menu_item_new_with_label("Screen");
                    680:   gtk_widget_show(menu_item);
                    681:   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
                    682:   gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_item);
                    683: 
                    684:   /* create an event box for the framebuffer area: */
                    685:   screen->tme_gtk_screen_event_box
                    686:     = gtk_event_box_new();
                    687: 
                    688:   /* pack the event box into the outer vertical packing box: */
                    689:   gtk_box_pack_start(GTK_BOX(screen->tme_gtk_screen_vbox0), 
                    690:                     screen->tme_gtk_screen_event_box,
                    691:                     FALSE, FALSE, 0);
                    692: 
                    693:   /* show the event box: */
                    694:   gtk_widget_show(screen->tme_gtk_screen_event_box);
                    695: 
                    696:   /* create a GdkImage of an alternating-bits area.  we must use
                    697:      malloc() here since this memory will end up as part of an XImage,
                    698:      and X will call free() on it: */
                    699:   bitmap_data = (tme_uint8_t *)
                    700:     malloc((BLANK_SIDE * BLANK_SIDE) / 8);
                    701:   assert(bitmap_data != NULL);
                    702:   for (y = 0;
                    703:        y < BLANK_SIDE;
                    704:        y++) {
                    705:     memset(bitmap_data
                    706:           + (y * BLANK_SIDE / 8),
                    707:           (y & 1
                    708:            ? 0x33
                    709:            : 0xcc),
                    710:           (BLANK_SIDE / 8));
                    711:   }
                    712:   screen->tme_gtk_screen_gdkimage
                    713:     = gdk_image_new_bitmap(gdk_visual_get_system(),
                    714:                           bitmap_data,
                    715:                           BLANK_SIDE,
                    716:                           BLANK_SIDE);
                    717: 
                    718:   /* create the GtkImage for the framebuffer area: */
                    719:   screen->tme_gtk_screen_gtkimage
                    720:     = gtk_image_new_from_image(screen->tme_gtk_screen_gdkimage, NULL);
                    721: 
                    722:   /* add the GtkImage to the event box: */
                    723:   gtk_container_add(GTK_CONTAINER(screen->tme_gtk_screen_event_box), 
                    724:                    screen->tme_gtk_screen_gtkimage);
                    725: 
                    726:   /* show the GtkImage: */
                    727:   gtk_widget_show(screen->tme_gtk_screen_gtkimage);
                    728: 
                    729:   /* show the outer vertical packing box: */
                    730:   gtk_widget_show(screen->tme_gtk_screen_vbox0);
                    731: 
                    732:   /* show the top-level window: */
                    733:   gtk_widget_show(screen->tme_gtk_screen_window);
                    734: 
                    735:   /* there is no translation function: */
                    736:   screen->tme_gtk_screen_fb_xlat = NULL;
                    737: 
                    738:   /* attach the mouse to this screen: */
                    739:   _tme_gtk_mouse_attach(screen);
                    740: 
                    741:   /* attach the keyboard to this screen: */
                    742:   _tme_gtk_keyboard_attach(screen);
                    743: 
                    744:   return (screen);
                    745: }
                    746: 
                    747: /* this breaks a framebuffer connection: */
                    748: static int
                    749: _tme_gtk_screen_connection_break(struct tme_connection *conn, unsigned int state)
                    750: {
                    751:   abort();
                    752: }
                    753: 
                    754: /* this makes a new framebuffer connection: */
                    755: static int
                    756: _tme_gtk_screen_connection_make(struct tme_connection *conn,
                    757:                                unsigned int state)
                    758: {
                    759:   struct tme_gtk_display *display;
                    760:   struct tme_gtk_screen *screen;
                    761:   struct tme_fb_connection *conn_fb;
                    762:   struct tme_fb_connection *conn_fb_other;
                    763: 
                    764:   /* recover our data structures: */
                    765:   display = (struct tme_gtk_display *) conn->tme_connection_element->tme_element_private;
                    766:   conn_fb = (struct tme_fb_connection *) conn;
                    767:   conn_fb_other = (struct tme_fb_connection *) conn->tme_connection_other;
                    768: 
                    769:   /* both sides must be framebuffer connections: */
                    770:   assert(conn->tme_connection_type
                    771:         == TME_CONNECTION_FRAMEBUFFER);
                    772:   assert(conn->tme_connection_other->tme_connection_type
                    773:         == TME_CONNECTION_FRAMEBUFFER);
                    774: 
                    775:   /* we're always set up to answer calls across the connection, so we
                    776:      only have to do work when the connection has gone full, namely
                    777:      taking the other side of the connection: */
                    778:   if (state == TME_CONNECTION_FULL) {
                    779: 
                    780:     /* lock our mutex: */
                    781:     tme_mutex_lock(&display->tme_gtk_display_mutex);
                    782: 
                    783:     /* if our initial screen is already connected, make a new screen: */
                    784:     screen = display->tme_gtk_display_screens;
                    785:     if (screen->tme_gtk_screen_fb != NULL) {
                    786:       screen = _tme_gtk_screen_new(display);
                    787:     }
                    788: 
                    789:     /* save our connection: */
                    790:     screen->tme_gtk_screen_fb = conn_fb;
                    791: 
                    792:     /* unlock our mutex: */
                    793:     tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    794: 
                    795:     /* call our mode change function: */
                    796:     _tme_gtk_screen_mode_change(conn_fb);
                    797:   }
                    798: 
                    799:   return (TME_OK);
                    800: }
                    801: 
                    802: /* this makes a new connection side for a GTK screen: */
                    803: int
                    804: _tme_gtk_screen_connections_new(struct tme_gtk_display *display, 
                    805:                                struct tme_connection **_conns)
                    806: {
                    807:   struct tme_fb_connection *conn_fb;
                    808:   struct tme_connection *conn;
                    809: 
                    810:   /* allocate a new framebuffer connection: */
                    811:   conn_fb = tme_new0(struct tme_fb_connection, 1);
                    812:   conn = &conn_fb->tme_fb_connection;
                    813:   
                    814:   /* fill in the generic connection: */
                    815:   conn->tme_connection_next = *_conns;
                    816:   conn->tme_connection_type = TME_CONNECTION_FRAMEBUFFER;
                    817:   conn->tme_connection_score = tme_fb_connection_score;
                    818:   conn->tme_connection_make = _tme_gtk_screen_connection_make;
                    819:   conn->tme_connection_break = _tme_gtk_screen_connection_break;
                    820: 
                    821:   /* fill in the framebuffer connection: */
                    822:   conn_fb->tme_fb_connection_mode_change = _tme_gtk_screen_mode_change;
                    823: 
                    824:   /* return the connection side possibility: */
                    825:   *_conns = conn;
                    826: 
                    827:   /* done: */
                    828:   return (TME_OK);
                    829: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.