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