]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dope/server/common/vscreen.c
update
[l4.git] / l4 / pkg / dope / server / common / vscreen.c
1 /*
2  * \brief   DOpE VScreen widget module
3  * \date    2002-11-13
4  * \author  Norman Feske <nf2@inf.tu-dresden.de>
5  */
6
7 /*
8  * Copyright (C) 2002-2004  Norman Feske  <nf2@os.inf.tu-dresden.de>
9  * Technische Universitaet Dresden, Operating Systems Research Group
10  *
11  * This file is part of the DOpE package, which is distributed under
12  * the  terms  of the  GNU General Public Licence 2.  Please see the
13  * COPYING file for details.
14  */
15
16 struct vscreen;
17 #define WIDGET struct vscreen
18
19 #include "dopestd.h"
20 #include "appman.h"
21 #include "thread.h"
22 #include "scheduler.h"
23 #include "widget_data.h"
24 #include "widget_help.h"
25 #include "gfx.h"
26 #include "redraw.h"
27 #include "vscreen.h"
28 #include "vscr_server.h"
29 #include "fontman.h"
30 #include "script.h"
31 #include "widman.h"
32 #include "userstate.h"
33 #include "messenger.h"
34 #include "keycodes.h"
35 #include "window.h"
36
37 #include <l4/re/env.h>
38
39 #define MAX_IDENTS 40
40
41 #define VSCR_MOUSEMODE_FREE    0
42 #define VSCR_MOUSEMODE_GRAB    1
43 #define VSCR_MOUSEMODE_GRABBED 2
44
45 #define VSCR_UPDATE_MOUSE_X   0x1
46 #define VSCR_UPDATE_MOUSE_Y   0x2
47
48 static struct scheduler_services   *sched;
49 static struct widman_services      *widman;
50 static struct script_services      *script;
51 static struct redraw_services      *redraw;
52 static struct appman_services      *appman;
53 static struct gfx_services         *gfx;
54 static struct messenger_services   *msg;
55 static struct userstate_services   *userstate;
56 static struct thread_services      *thread;
57 static struct vscr_server_services *vscr_server;
58 static struct fontman_services     *font;
59
60 struct vscreen_data {
61         long    update_flags;
62         char   *server_ident;        /* associated vscreen server identifier */
63         THREAD *server_thread;
64         MUTEX  *sync_mutex;
65         s8      bpp;                 /* bits per pixel                               */
66         s32     xres, yres;          /* virtual screen dimensions                    */
67         s16     fps;                 /* frames per second                            */
68         char    smb_ident[64];       /* shared memory block identifier               */
69         void   *pixels;              /* pointer to page aligned pixel buffer         */
70         GFX_CONTAINER *image;        /* image representation (for drawing)           */
71         s16     grabmouse;           /* mouse grab mode flag 0=free 1=grab 2=grabbed */
72         VSCREEN *share_next;         /* next vscreen widget with shared buffer       */
73         s32     vw, vh;              /* view size                                    */
74         s32     curr_vx, curr_vy;    /* current view position                        */
75         s32     next_vx, next_vy;    /* next view position                           */
76 };
77
78 static int msg_cnt, msg_fid;    /* fade cnt and font of on-screen msg */
79 static int msg_x, msg_y;        /* position of onscreen message       */
80 static int msg_w, msg_h;        /* size of onscreen message area      */
81 static char *msg_txt;           /* text of the onscreen message       */
82
83 static int vs_mx, vs_my;        /* mouse position of grabbed mouse */
84
85 int init_vscreen(struct dope_services *d);
86
87
88 /*************************
89  *** UTILITY FUNCTIONS ***
90  *************************/
91
92 /*** EXCLUDE VSCREEN WIDGET FROM RING LIST OF VSCREENS WITH A SHARED BUFFER ***/
93 static void vscr_share_exclude(VSCREEN *vs) {
94         VSCREEN *prev = vs->vd->share_next;
95         while ((prev) && (prev->vd->share_next!=vs)) prev = prev->vd->share_next;
96         if (prev) prev->vd->share_next = vs->vd->share_next;
97         vs->vd->share_next = NULL;
98
99         if (vs->vd->image) {
100                 gfx->dec_ref(vs->vd->image);
101                 vs->vd->image = NULL;
102         }
103 }
104
105
106 /*** INCLUDE NEW VSCREEN IN RING LIST OF VSCREENS WITH A SHARED BUFFER ***
107  *
108  * \param vs   member of the new desired ring list
109  * \param new  new vscreen widget to join the list
110  */
111 static void vscr_share_join(VSCREEN *vs, VSCREEN *new) {
112         if (new->vd->share_next) vscr_share_exclude(new);
113         new->vd->share_next = vs->vd->share_next;
114         vs->vd->share_next = new;
115         if (!new->vd->share_next) new->vd->share_next = vs;
116 }
117
118
119 /******************************
120  *** GENERAL WIDGET METHODS ***
121  ******************************/
122
123 /*** DRAW VSCREEN WIDGET ***/
124 static int vscr_draw(VSCREEN *vs, struct gfx_ds *ds, long x, long y, WIDGET *origin) {
125         x += vs->wd->x;
126         y += vs->wd->y;
127
128         if (origin == vs) return 1;
129         if (origin) return 0;
130
131         gfx->push_clipping(ds, x, y, vs->wd->w, vs->wd->h);
132         if (vs->vd->image) {
133                 float xratio = (float)vs->wd->w / (float)vs->vd->vw;
134                 float yratio = (float)vs->wd->h / (float)vs->vd->vh;
135                 int sx = xratio * vs->vd->curr_vx;
136                 int sy = yratio * vs->vd->curr_vy;
137                 int sw = xratio * vs->vd->xres;
138                 int sh = yratio * vs->vd->yres;
139
140                 gfx->draw_img(ds, x - sx, y - sy, sw, sh, vs->vd->image, 255);
141         }
142         if ((vs->vd->grabmouse == VSCR_MOUSEMODE_GRABBED) && (msg_cnt)) {
143                 int v = msg_cnt;
144                 gfx->draw_string(ds, x+msg_x-1, y+msg_y, GFX_RGB(0, 0, 0), 0, msg_fid, msg_txt);
145                 gfx->draw_string(ds, x+msg_x+1, y+msg_y, GFX_RGB(0, 0, 0), 0, msg_fid, msg_txt);
146                 gfx->draw_string(ds, x+msg_x, y+msg_y-1, GFX_RGB(0, 0, 0), 0, msg_fid, msg_txt);
147                 gfx->draw_string(ds, x+msg_x, y+msg_y+1, GFX_RGB(0, 0, 0), 0, msg_fid, msg_txt);
148                 gfx->draw_string(ds, x+msg_x, y+msg_y,   GFX_RGB(v, v, v), 0, msg_fid, msg_txt);
149         }
150         gfx->pop_clipping(ds);
151
152         return 1;
153 }
154
155
156 static void (*orig_update) (VSCREEN *vs);
157
158 /*** UPDATE WIDGET AFTER CHANGES OF ITS ATTRIBUTES ***/
159 static void vscr_update(VSCREEN *vs)
160 {
161   EVENT event;
162
163   if (vs->vd->update_flags & (VSCR_UPDATE_MOUSE_X | VSCR_UPDATE_MOUSE_Y))
164     {
165       if (!(vs->vd->update_flags & VSCR_UPDATE_MOUSE_X))
166         vs_mx = userstate->get_mx();
167
168       if (!(vs->vd->update_flags & VSCR_UPDATE_MOUSE_Y))
169         vs_my = userstate->get_my();
170
171       event.time  = l4_kip_clock(l4re_kip());
172       event.type  = L4RE_EV_ABS;
173       event.code  = L4RE_ABS_X;
174       event.value = vs_mx - vs->gen->get_abs_x(vs);
175       vs->gen->handle_event(vs, &event, NULL);
176
177       event.type  = L4RE_EV_ABS;
178       event.code  = L4RE_ABS_Y;
179       event.value = vs_my - vs->gen->get_abs_y(vs);
180       vs->gen->handle_event(vs, &event, NULL);
181
182       /* warp mouse to new position and handle the synthetic event */
183       userstate->set_pos(vs_mx, vs_my);
184   }
185   orig_update(vs);
186   vs->vd->update_flags = 0;
187 }
188
189
190 /*** TIMER TICK CALLBACK FOR GRAB USERSTATE ***
191  *
192  * This callback is used to fade out the mouse-release-message.
193  * The variable msg_cnt is set to 255 when the mouse is grabbed and faded
194  * down to zero. For each step the part of the widget which displays the
195  * message is redrawn.
196  */
197 #if 0
198 static void grab_tick_callback(WIDGET *w, int dx, int dy) {
199   (void)dx; (void)dy;
200         if (msg_cnt > 70) {
201                 msg_cnt -= 2;
202                 if (w->vd->fps == 0) redraw->draw_widgetarea(w, msg_x-1, msg_y-1, msg_x+msg_w+1, msg_y+msg_h+1);
203         } else if (msg_cnt > 0) {
204                 msg_cnt = 0;
205                 if (w->vd->fps == 0) redraw->draw_widgetarea(w, msg_x-1, msg_y-1, msg_x+msg_w+1, msg_y+msg_h+1);
206         } else {
207                 msg_cnt = 0;
208         }
209 }
210 #endif
211
212
213 /*** HANDLE EVENTS ***
214  *
215  * We have to take care about the mouse grab mode of the VScreen widget.
216  * In grab-mode the mouse is grabbed by any press event onto the widget.
217  * When grabbed, the mouse can be discharged by pressing [pause]. All
218  * other events go through the normal way.
219  */
220 static void (*orig_handle_event)(WIDGET *w, EVENT *, WIDGET *from);
221 static void vscr_handle_event(VSCREEN *vs, EVENT *e, WIDGET *from) {
222 #if 0
223         unsigned long m;
224         s32 app_id;
225         if (e->type == EVENT_PRESS) {
226                 /* transition from grabbed to grab */
227                 if (vs->vd->grabmouse == VSCR_MOUSEMODE_GRABBED) {
228                         if (e->code == L4RE_KEY_PAUSE) {
229                                 vs->vd->grabmouse = VSCR_MOUSEMODE_GRAB;
230                                 m = vs->gen->get_bind_msg(vs, "discharge");
231                                 app_id = vs->gen->get_app_id(vs);
232                                 if (m) msg->send_action_event(app_id, "discharge", m);
233                                 msg_cnt = 0;
234                                 redraw->draw_widgetarea(vs, msg_x, msg_y, msg_x + msg_w, msg_y + msg_h);
235                                 userstate->idle();
236                                 return;
237                         }
238                 /* transition to grabbed mouse */
239                 } else if (vs->vd->grabmouse == VSCR_MOUSEMODE_GRAB) {
240                         WINDOW *w;
241                         
242                         /* top associated window */
243                         w = (WINDOW *)vs->gen->get_window(vs);
244                         if (w) w->win->top(w);
245
246                         vs->vd->grabmouse = VSCR_MOUSEMODE_GRABBED;
247                         m = vs->gen->get_bind_msg(vs, "catch");
248                         app_id = vs->gen->get_app_id(vs);
249                         if (m) msg->send_action_event(app_id, "catch", m);
250                         msg_x = (vs->wd->w - msg_w)/2;
251                         msg_y = (vs->wd->h - msg_h)/2;
252                         userstate->grab(vs, grab_tick_callback);
253                         msg_cnt = 255;
254                         return;
255                 }
256         }
257 #endif
258         /* scale values of motion event */
259         if (e->type == L4RE_EV_ABS)
260           {
261             float ratio = 1;
262             if (e->code == L4RE_ABS_X)
263               ratio = (float)vs->vd->xres / (float)vs->wd->w;
264             else if (e->code == L4RE_ABS_Y)
265               ratio = (float)vs->vd->yres / (float)vs->wd->h;
266
267             e->value = (float)e->value  * ratio;
268           }
269         orig_handle_event(vs, e, from);
270 }
271
272
273 /*** RELEASE VSCREEN DATA ***
274  *
275  * Eventually, we have to exclude the vscreen from
276  * the ring list of vscreens which share one buffer.
277  */
278 static void vscr_free_data(VSCREEN *vs) {
279
280         /* shutdown vscreen server thread */
281         if (vs->vd->server_thread)
282                 thread->kill_thread(vs->vd->server_thread);
283
284         vs->vd->server_thread = NULL;
285
286         /* free the mouse if it is currently grabbed inside the vscreen widget */
287         if ((userstate->get() == USERSTATE_GRAB) && (userstate->get_selected() == vs))
288                 userstate->idle();
289         
290         if (vs->wd->ref_cnt == 0) vscr_share_exclude(vs);
291 }
292
293
294 /*** RETURN WIDGET TYPE IDENTIFIER ***/
295 static char *vscr_get_type(VSCREEN *vs) {
296   (void)vs;
297         return "VScreen";
298 }
299
300
301 /********************************
302  *** VSCREEN SPECIFIC METHODS ***
303  ********************************/
304
305 /*** REGISTER VSCREEN WIDGET SERVER ***/
306 static void vscr_reg_server(VSCREEN *vs, char *new_server_ident) {
307         if (!new_server_ident) return;
308         INFO(printf("Vscreen(reg_server): register Vscreen server with ident=%s\n", new_server_ident));
309         vs->vd->server_ident = new_server_ident;
310 }
311
312
313 /*** RETURN VSCREEN WIDGET SERVER ***/
314 static char *vscr_get_server(VSCREEN *vs) {
315
316         /* allocate thread id for server thread */
317         vs->vd->server_thread = thread->alloc_thread();
318
319         /* start widget server */
320         if (vscr_server && vs->vd->server_thread)
321                 vscr_server->start(vs->vd->server_thread, vs);
322
323         INFO(printf("VScreen(get_server): server_ident = %s\n", vs->vd->server_ident));
324         return vs->vd->server_ident;
325 }
326
327
328 /*** SET UPDATE RATE OF THE VSCREEN WIDGET ***/
329 static void vscr_set_framerate(VSCREEN *vs, s32 framerate) {
330
331         if (framerate == 0) {
332                 sched->remove(vs);
333         } else {
334                 sched->add(vs, 1000/framerate);
335                 sched->set_sync_mutex(vs, vs->vd->sync_mutex);
336                 vs->vd->fps = framerate;
337         }
338 }
339
340
341 /*** REQUEST CURRENT UPDATE RATE ***/
342 static s32 vscr_get_framerate(VSCREEN *vs) {
343         return vs->vd->fps;
344 }
345
346
347 /*** SET VSCREEN MOUSE X POSITION ***/
348 static void vscr_set_mx(VSCREEN *vs, s32 new_mx) {
349         if (vs->vd->grabmouse != VSCR_MOUSEMODE_GRABBED) return;
350         vs_mx = new_mx + vs->gen->get_abs_x(vs);
351         vs->vd->update_flags |= VSCR_UPDATE_MOUSE_X;
352 }
353
354
355 /*** REQUEST VSCREEN MOUSE X POSITION ***/
356 static s32 vscr_get_mx(VSCREEN *vs) {
357         if (vs->vd->grabmouse != VSCR_MOUSEMODE_GRABBED) return 0;
358         return vs_mx - vs->gen->get_abs_x(vs);
359 }
360
361
362 /*** SET VSCREEN MOUSE Y POSITION ***/
363 static void vscr_set_my(VSCREEN *vs, s32 new_my) {
364         if (vs->vd->grabmouse != VSCR_MOUSEMODE_GRABBED) return;
365         vs_my = new_my + vs->gen->get_abs_y(vs);
366         vs->vd->update_flags |= VSCR_UPDATE_MOUSE_Y;
367 }
368
369
370 /*** SET WIDTH OF A VSCREEN TO A FIXED VALUE ***/
371 static void vscr_set_fixw(VSCREEN *vs, char *new_fixw) {
372         if (!new_fixw) return;
373         if (dope_streq("none", new_fixw, 4)) {
374                 vs->wd->min_w = 0;
375                 vs->wd->max_w = 99999;
376         } else {
377                 vs->wd->min_w = vs->wd->max_w = atol(new_fixw);
378         }
379         vs->wd->update |= WID_UPDATE_MINMAX;
380 }
381
382
383 /*** SET HEIGHT OF A VSCREEN TO A FIXED VALUE ***/
384 static void vscr_set_fixh(VSCREEN *vs, char *new_fixh) {
385         if (!new_fixh) return;
386         if (dope_streq("none", new_fixh, 4)) {
387                 vs->wd->min_h = 0;
388                 vs->wd->max_h = 99999;
389         } else {
390                 vs->wd->min_h = vs->wd->max_h = atol(new_fixh);
391         }
392         vs->wd->update |= WID_UPDATE_MINMAX;
393 }
394
395
396 /*** REQUEST VSCREEN MOUSE Y POSITION ***/
397 static s32 vscr_get_my(VSCREEN *vs) {
398         if (vs->vd->grabmouse != VSCR_MOUSEMODE_GRABBED) return 0;
399         return vs_my - vs->gen->get_abs_y(vs);
400 }
401
402
403 /*** SET MOUSE GRAB MODE OF THE VSCREEN WIDGET ***/
404 static void vscr_set_grabmouse(VSCREEN *vs, s32 grab_flag) {
405         vs->vd->grabmouse = grab_flag ? VSCR_MOUSEMODE_GRAB : VSCR_MOUSEMODE_FREE;
406 }
407
408
409 /*** REQUEST MOUSE GRAB MODE ***/
410 static s32 vscr_get_grabmouse(VSCREEN *vs) {
411         if (vs->vd->grabmouse == VSCR_MOUSEMODE_FREE) return 0;
412         return 1;
413 }
414
415
416 /*** TEST IF A GIVEN GRAPHICS MODE IS VALID ***/
417 static s32 vscr_probe_mode(VSCREEN *vs, s32 width, s32 height, char *mode) {
418   (void)vs;
419         if ((!dope_streq(mode, "RGB16",  6))
420          && (!dope_streq(mode, "YUV420", 7))
421          && (!dope_streq(mode, "RGBA32", 7))) return 0;
422         if (width*height <= 0) return 0;
423         return 1;
424 }
425
426
427 /*** SET GRAPHICS MODE ***/
428 static s32 vscr_set_mode(VSCREEN *vs, s32 width, s32 height, char *mode) {
429         int type = 0;
430
431         if (!vscr_probe_mode(vs, width, height, mode)) return 0;
432
433         /* destroy old image buffer and reset values */
434         switch (vs->vd->bpp) {
435         case 16:
436         case 32:
437                 if (vs->vd->image) gfx->dec_ref(vs->vd->image);
438         }
439
440         vs->vd->bpp     = 0;
441         vs->vd->xres    = 0;
442         vs->vd->yres    = 0;
443         vs->vd->pixels  = NULL;
444         vs->vd->image   = NULL;
445         vs->vd->vw      = vs->vd->vh      = 0;
446         vs->vd->curr_vx = vs->vd->next_vx = 0;
447         vs->vd->curr_vy = vs->vd->next_vy = 0;
448
449         /* create new frame buffer image */
450         if (dope_streq("RGB16",  mode, 6)) type = GFX_IMG_TYPE_RGB16;
451         if (dope_streq("RGBA32", mode, 7)) type = GFX_IMG_TYPE_RGBA32;
452         if (dope_streq("YUV420", mode, 7)) type = GFX_IMG_TYPE_YUV420;
453
454         if (!type) {
455                 ERROR(printf("VScreen(set_mode): mode %s not supported!\n", mode);)
456                 return 0;
457         }
458
459         if ((vs->vd->image = gfx->alloc_img(width, height, type))) {
460                 vs->vd->xres   = width;
461                 vs->vd->yres   = height;
462                 vs->vd->vw     = width;
463                 vs->vd->vh     = height;
464                 vs->vd->pixels = gfx->map(vs->vd->image);
465                 gfx->get_ident(vs->vd->image, &vs->vd->smb_ident[0]);
466         } else {
467                 ERROR(printf("VScreen(set_mode): out of memory!\n");)
468                 return 0;
469         }
470
471         if (type == GFX_IMG_TYPE_RGBA32)
472                 vs->wd->flags &= ~WID_FLAGS_CONCEALING;
473         else
474                 vs->wd->flags |= WID_FLAGS_CONCEALING;
475
476         vs->gen->update(vs);
477         return 1;
478 }
479
480
481 /*** WAIT FOR THE NEXT SYNC ***/
482 static void vscr_waitsync(VSCREEN *vs) {
483         thread->mutex_down(vs->vd->sync_mutex);
484 }
485
486
487 /*** UPDATE A SPECIFIED AREA OF THE WIDGET ***/
488 static void vscr_refresh(VSCREEN *vs, s32 x, s32 y, s32 w, s32 h) {
489         VSCREEN *last = vs;
490         int sx1, sy1, sx2, sy2;
491         float mx, my;
492
493         int cnt = 1;
494         if (vs->vd->share_next) {
495                 while ((vs = vs->vd->share_next) != last) cnt++;
496         }
497
498         if (w == -1) w = vs->vd->xres;
499         if (h == -1) h = vs->vd->yres;
500         if ((w<1) || (h<1)) return;
501         
502         /* refresh all vscreens which share the same pixel buffer */
503         while (cnt--) {
504                 mx = (float)vs->wd->w / (float)vs->vd->xres;
505                 my = (float)vs->wd->h / (float)vs->vd->yres;
506                 sx1 = x*mx;
507                 sy1 = y*my;
508                 sx2 = (int)((x + w)*mx);
509                 sy2 = (int)((y + h)*my);
510                 redraw->draw_widgetarea(vs, sx1, sy1, sx2, sy2);
511                 vs = vs->vd->share_next;
512         }
513 }
514
515
516 /*** MAP VSCREEN BUFFER TO ANOTHER THREAD'S ADDRESS SPACE ***/
517 static char *vscr_map(VSCREEN *vs, char *dst_thread_ident) {
518   (void)dst_thread_ident;
519         s32 app_id;
520         char dst_th_buf[16];
521         THREAD *dst_th = (THREAD *)(void *)dst_th_buf;
522         
523         if (!vs->vd->image) return "Error: VScreen mode not initialized.";
524
525         /* if no valid thread identifier was suppied we map to the app's thread */
526         /*if (thread->ident2thread(dst_thread_ident, dst_th))*/ {
527                 app_id = vs->gen->get_app_id(vs);
528                 dst_th = appman->get_app_thread(app_id);
529         }
530         gfx->share(vs->vd->image, dst_th);
531         INFO(printf("VScreen(map): return vs->vd->smb_ident = %s\n", &vs->vd->smb_ident[0]));
532         return &vs->vd->smb_ident[0];
533 }
534
535
536 /*** SHARE IMAGE BUFFER WITH OTHER SPECIFIED VSCREEN ***/
537 static void vscr_share(VSCREEN *vs, VSCREEN *from) {
538         int img_type = 0;
539         GFX_CONTAINER *new_image;
540
541         /* exclude widget from its previous ring list of buffer-shared vscreen */
542         if (vs->vd->share_next) vscr_share_exclude(vs);
543
544         if (!from || !(new_image = from->vscr->get_image(from))) return;
545
546         /*
547          * Increment reference counter of new image before decrementing
548          * the reference counter of the old one. If both images are the
549          * same, we do not want to risk a reference counter of zero.
550          */
551         gfx->inc_ref(new_image);
552
553         /* replace old image with new one */
554         if (vs->vd->image) gfx->dec_ref(vs->vd->image);
555         vs->vd->image = new_image;
556
557         vs->vd->vw = vs->vd->xres = gfx->get_width(vs->vd->image);
558         vs->vd->vh = vs->vd->yres = gfx->get_height(vs->vd->image);
559         img_type = gfx->get_type(vs->vd->image);
560         switch (img_type) {
561         case GFX_IMG_TYPE_RGB16:
562                 vs->vd->bpp = 16;
563                 break;
564         case GFX_IMG_TYPE_RGBA32:
565                 vs->vd->bpp = 32;
566                 break;
567         case GFX_IMG_TYPE_YUV420:
568                 vs->vd->bpp = 12;
569                 break;
570         }
571         vs->vd->pixels = gfx->map(vs->vd->image);
572
573         vs->gen->set_w(vs, vs->vd->xres);
574         vs->gen->set_h(vs, vs->vd->yres);
575         vs->gen->updatepos(vs);
576
577         /* join the new ring list of buffer sharing vscreens */
578         vscr_share_join(from, vs);
579 }
580
581
582 static GFX_CONTAINER *vscr_get_image(VSCREEN *vs) {
583         return vs->vd->image;
584 }
585
586
587 static struct widget_methods gen_methods;
588 static struct vscreen_methods vscreen_methods = {
589         vscr_reg_server,
590         vscr_waitsync,
591         vscr_refresh,
592         vscr_get_image,
593 };
594
595
596 /*************************
597  *** SERVICE FUNCTIONS ***
598  *************************/
599
600 static VSCREEN *create(void) {
601
602         VSCREEN *new = ALLOC_WIDGET(struct vscreen);
603         SET_WIDGET_DEFAULTS(new, struct vscreen, &vscreen_methods);
604
605         /* set widget type specific data */
606         new->vd->sync_mutex = thread->create_mutex(1);  /* locked */
607         new->wd->flags |= WID_FLAGS_CONCEALING | WID_FLAGS_EDITABLE;
608         return new;
609 }
610
611
612 /****************************************
613  *** SERVICE STRUCTURE OF THIS MODULE ***
614  ****************************************/
615
616 static struct vscreen_services services = {
617         create
618 };
619
620
621 /**************************
622  *** MODULE ENTRY POINT ***
623  **************************/
624
625 static void build_script_lang(void) {
626         void *widtype;
627
628         widtype = script->reg_widget_type("VScreen", (void *(*)(void))create);
629
630         script->reg_widget_method(widtype, "long probemode(long width, long height, string mode)", vscr_probe_mode);
631         script->reg_widget_method(widtype, "long setmode(long width, long height, string mode)", vscr_set_mode);
632         script->reg_widget_method(widtype, "string getserver()", vscr_get_server);
633         script->reg_widget_method(widtype, "string map(string thread=\"caller\")", vscr_map);
634         script->reg_widget_method(widtype, "void refresh(long x=0, long y=0, long w=-1, long h=-1)", vscr_refresh);
635         script->reg_widget_method(widtype, "void share(Widget from)", vscr_share);
636
637         script->reg_widget_attrib(widtype, "long framerate", vscr_get_framerate, vscr_set_framerate, gen_methods.update);
638         script->reg_widget_attrib(widtype, "string fixw", NULL, vscr_set_fixw, gen_methods.update);
639         script->reg_widget_attrib(widtype, "string fixh", NULL, vscr_set_fixh, gen_methods.update);
640         script->reg_widget_attrib(widtype, "long mousex", vscr_get_mx, vscr_set_mx, gen_methods.update);
641         script->reg_widget_attrib(widtype, "long mousey", vscr_get_my, vscr_set_my, gen_methods.update);
642         script->reg_widget_attrib(widtype, "boolean grabmouse", vscr_get_grabmouse, vscr_set_grabmouse, gen_methods.update);
643         widman->build_script_lang(widtype, &gen_methods);
644 }
645
646
647 int init_vscreen(struct dope_services *d) {
648
649         gfx         = d->get_module("Gfx 1.0");
650         script      = d->get_module("Script 1.0");
651         widman      = d->get_module("WidgetManager 1.0");
652         redraw      = d->get_module("RedrawManager 1.0");
653         appman      = d->get_module("ApplicationManager 1.0");
654         thread      = d->get_module("Thread 1.0");
655         sched       = d->get_module("Scheduler 1.0");
656         vscr_server = d->get_module("VScreenServer 1.0");
657         msg         = d->get_module("Messenger 1.0");
658         userstate   = d->get_module("UserState 1.0");
659         font        = d->get_module("FontManager 1.0");
660
661         /* define general widget functions */
662         widman->default_widget_methods(&gen_methods);
663
664         orig_update          = gen_methods.update;
665         orig_handle_event    = gen_methods.handle_event;
666         
667         gen_methods.get_type     = vscr_get_type;
668         gen_methods.draw         = vscr_draw;
669         gen_methods.update       = vscr_update;
670         gen_methods.free_data    = vscr_free_data;
671         gen_methods.handle_event = vscr_handle_event;
672
673         build_script_lang();
674
675         msg_fid = 0;
676         msg_txt = "press [pause] to release mouse";
677         msg_w = font->calc_str_width(msg_fid, msg_txt);
678         msg_h = font->calc_str_height(msg_fid, msg_txt);
679
680         d->register_module("VScreen 1.0", &services);
681         return 1;
682 }