|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.