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