Project

General

Profile

1811q_20150906_1.txt

Sergey Ivanovskiy, 09/06/2015 07:51 PM

Download (24.8 KB)

 
1
=== added file 'src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js'
2
--- src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js	1970-01-01 00:00:00 +0000
3
+++ src/com/goldencode/p2j/ui/client/chui/driver/web/res/p2j.virtual_desktop.js	2015-09-06 23:04:05 +0000
4
@@ -0,0 +1,15 @@
5
+/*
6
+** Module   : p2j.virtual_desktop.js
7
+** Abstract : CHUI-specific virtual desktop module.
8
+**
9
+** Copyright (c) 2014-2015, Golden Code Development Corporation.
10
+** ALL RIGHTS RESERVED. Use is subject to license terms.
11
+**
12
+**         Golden Code Development Corporation
13
+**                 CONFIDENTIAL
14
+**
15
+** -#- -I- --Date-- ------------------------------Description----------------------------------
16
+** 001 SBI 20150906 The virtual desktop empty module.
17
+*/
18
+
19
+"use strict";
20

    
21
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html'
22
--- src/com/goldencode/p2j/ui/client/driver/web/index.html	2015-09-05 16:09:44 +0000
23
+++ src/com/goldencode/p2j/ui/client/driver/web/index.html	2015-09-06 21:12:01 +0000
24
@@ -12,6 +12,7 @@
25
       <script type="text/javascript" src="/common/p2j.sound.js"></script>
26
       <script type="text/javascript" src="/client/p2j.strokes.js"></script>
27
       <script type="text/javascript" src="/client/p2j.canvas_renderer.js"></script>
28
+      <script type="text/javascript" src="/client/p2j.virtual_desktop.js"></script>
29
       <script type="text/javascript" src="/client/p2j.mouse.js"></script>
30
       <script type="text/javascript" src="/client/p2j.screen.js"></script>
31
       <script type="text/javascript" src="/common/p2j.socket.js"></script>
32

    
33
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js'
34
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2015-09-05 16:09:44 +0000
35
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js	2015-09-06 22:04:21 +0000
36
@@ -14,6 +14,18 @@
37
 
38
 "use strict";
39
 
40
+/**
41
+ * Creates the canvas renderer.
42
+ * 
43
+ * @param    {HtmlCanvasElement} canvas
44
+ *           The html canvas element.
45
+ * @param    {CanvasRenderingContext2D} ctx
46
+ *           The canvas 2D graphics context on which to draw.
47
+ * @param    {LinesStroke} strokesManager
48
+ *           The stroke manager
49
+ * @param    {Object} logger
50
+ *           The p2j logger.
51
+ */
52
 function CanvasRenderer(canvas, ctx, strokesManager, logger)
53
 {
54
    this.canvas = canvas;
55

    
56
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js'
57
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-09-05 16:09:44 +0000
58
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-09-06 23:31:23 +0000
59
@@ -17,6 +17,7 @@
60
 **                  added a drawing image operation.
61
 ** 004 GES 20150818 Added more GUI support including fonts, cursors, z-order, mouse events.
62
 *                   Fixed many problems with the initial implementation. Implemented SET_ICON.
63
+*                   Added the draggable task bar implementation.
64
 */
65
 
66
 "use strict";
67
@@ -132,6 +133,15 @@
68
    var strokesManager = new LineStrokes();
69
    
70
    /**
71
+    * Holds the virtual desktop with task bar and bottom and right drop zones.
72
+    */
73
+   var desktop;
74
+
75
+   /**
76
+    * Holds the task bar.
77
+    */
78
+   var taskBar;
79
+   /**
80
     * Constructor for a Window class that represents a Progress 4GL window instance.
81
     *
82
     * @param   wid
83
@@ -694,6 +704,7 @@
84
                   loadedImages.set(key, message.subarray(imgDataOffset, imgDataOffset + pixelsInBytes));
85
                }
86
                this.canvasRenderer.drawImage(this.ctx, x, y, width, height, imgData, imgDataOffset);
87
+               taskBar.draw();
88
                break;
89
             case ops.FILL_ROUND_RECT:
90
                x        = p2j.socket.readInt32BinaryMessage(message, idx + 1);
91
@@ -813,6 +824,7 @@
92
             case ops.SET_TITLE:
93
                var title = p2j.socket.readStringBinaryMessage(message, idx + 1);
94
                this.title = title;
95
+               taskBar.draw();
96
                // TODO: force taskbar to repaint
97
                break;
98
             case ops.SET_ICON:
99
@@ -833,7 +845,7 @@
100
                   this.iconWidth  = iconWidth;
101
                   this.iconHeight = iconHeight;
102
                }
103
-               
104
+               taskBar.setIconForTask(this.id, loadedImages.get(this.iconId));
105
                break;
106
             default:
107
                if (typeof type !== "undefined")
108
@@ -948,7 +960,7 @@
109
     */
110
    Window.prototype.iconify = function()
111
    {
112
-      // TODO: implement this
113
+      taskBar.iconify(this.id);
114
    };
115
    
116
    /**
117
@@ -960,22 +972,23 @@
118
 
119
       // TODO: this message needs to be sent by the taskbar, when the window is being deiconified
120
       // this API should just perform whatever actions are required (i.e. show the window, etc)
121
-      var message = new Uint8Array(6);
122
-
123
-      // message type
124
-      message[0] = 0x10;
125
-      offset = offset + 1;
126
-      
127
-      // 0. the window ID
128
-      p2j.socket.writeInt32BinaryMessage(message, offset, wThis.id);
129
-      offset = offset + 4;
130
-      
131
-      // 1. the iconification state
132
-      message[offset] = 0;
133
-      offset = offset + 1;
134
-      
135
-      // send the mouse event
136
-      p2j.socket.send(message);
137
+//      var message = new Uint8Array(6);
138
+//
139
+//      // message type
140
+//      message[0] = 0x10;
141
+//      offset = offset + 1;
142
+//      
143
+//      // 0. the window ID
144
+//      p2j.socket.writeInt32BinaryMessage(message, offset, this.id);
145
+//      offset = offset + 4;
146
+//      
147
+//      // 1. the iconification state
148
+//      message[offset] = 0;
149
+//      offset = offset + 1;
150
+//      
151
+//      // send the mouse event
152
+//      p2j.socket.send(message);
153
+      taskBar.deiconify(this.id);
154
    };
155
    
156
    /**
157
@@ -1324,6 +1337,9 @@
158
       // add to the z-order list
159
       addZOrderEntry(wid, newwin);
160
       
161
+      // creates new task icon widget for new window
162
+      taskBar.addTaskIcon(newwin);
163
+
164
       return newwin;
165
    };
166
    
167
@@ -1545,6 +1561,23 @@
168
    };
169
    
170
    /**
171
+    * Sends the active window state to the server.
172
+    * 
173
+    * @param    {Number} windowId
174
+    *           The target windowId
175
+    */
176
+   function sendWindowStateActive(windowId)
177
+   {
178
+      var message = new Uint8Array(6);
179
+
180
+      message[0] = 0x10;
181
+      p2j.socket.writeInt32BinaryMessage(message, 1, windowId);
182
+      // 1. the iconification state
183
+      message[5] = 0;
184
+      p2j.socket.send(message);
185
+   }
186
+
187
+   /**
188
     * Initialize module.
189
     *  
190
     * @param {object} cfg configuration.
191
@@ -1556,6 +1589,13 @@
192
       
193
       // enable all OS events
194
       me.enableOsEvents(true);
195
+      
196
+      desktop = new VirtualDesktop(
197
+            sendWindowStateActive,
198
+            [194, 194, 194],
199
+            [128, 128, 128],
200
+            p2j.logger);
201
+      taskBar = desktop.getTaskBar();
202
    };
203
 
204
    /**
205

    
206
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js'
207
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js	1970-01-01 00:00:00 +0000
208
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.virtual_desktop.js	2015-09-06 23:44:56 +0000
209
@@ -0,0 +1,593 @@
210
+/*
211
+** Module   : p2j.virtual_desktop.js
212
+** Abstract : GUI-specific virtual desktop to create task bar and drop zones
213
+**
214
+** Copyright (c) 2014-2015, Golden Code Development Corporation.
215
+** ALL RIGHTS RESERVED. Use is subject to license terms.
216
+**
217
+**         Golden Code Development Corporation
218
+**                 CONFIDENTIAL
219
+**
220
+** -#- -I- --Date-- ------------------------------Description----------------------------------
221
+** 001 SBI 20150906 The virtual desktop to create task bar and drop zones.
222
+*/
223
+
224
+"use strict";
225
+
226
+
227
+
228
+
229
+
230
+
231
+/**
232
+ * Creates the virtual desktop with dragged task bar and two drop zones: the bottom and the right
233
+ * according to this css style:
234
+ * 
235
+ *.right {
236
+ *   position: fixed;
237
+ *   top: 0px;
238
+ *   right: 0px;
239
+ *   height: 100%;
240
+ *   width: 40px;
241
+ *}
242
+ *.bottom {
243
+ *   position: fixed;
244
+ *   bottom: 0px;
245
+ *   height: 40px;
246
+ *   width: 100%;
247
+ *}
248
+ *.virtualDesktop {
249
+ *   position: fixed;
250
+ *   left: 0px;
251
+ *   top: 0px;
252
+ *}
253
+ *.canvas {
254
+ *   position: relative;
255
+ *   width: 100%;
256
+ *   height: 100%;
257
+ *}
258
+ *.dock {
259
+ *}
260
+ * 
261
+ * @param    {Function} taskIconOnClickCallback
262
+ *           The 1-argument function to send the active window state request to the server.
263
+ * @param    {Array} bg
264
+ *           The background task bar color. It is represented by the 3-elements array
265
+ *           filled with red, green and blue values from 0 to 255.
266
+ * @param    {Array} fg
267
+ *           The foreground task bar color for task icons. It is represented by the 3-elements array
268
+ *           filled with red, green and blue values from 0 to 255.
269
+ * @param    {Object} logger
270
+ *           The p2j global application logger.
271
+ */
272
+function VirtualDesktop(taskIconOnClickCallback, bg, fg, logger)
273
+{
274
+   /** task bar id*/
275
+   var TASK_BAR_ID = "taskBar";
276
+   /** drop zone class name*/
277
+   var DOCK_CLASS_NAME = "dock";
278
+   /** task bar side */
279
+   var TASK_BAR_WIDTH  = 42;
280
+
281
+   
282
+   /** the parent element for the virtual desktop */
283
+   var desktop = document.createElement("div");
284
+   
285
+   desktop.style["position"] = "fixed";
286
+   desktop.style["top"]  = "0px";
287
+   desktop.style["left"] = "0px";
288
+   var body = document.body;
289
+   body.appendChild(desktop);
290
+   var bottom = createBottomDropZone(DOCK_CLASS_NAME, TASK_BAR_WIDTH);
291
+   var taskBarPeer = createTaskBarPeer(TASK_BAR_ID);
292
+   bottom.appendChild(taskBarPeer);
293
+   desktop.appendChild(bottom);
294
+   desktop.appendChild(createRightDropZone(DOCK_CLASS_NAME, TASK_BAR_WIDTH));
295
+   
296
+   var taskBar = new TaskBar(taskBarPeer, bg, fg, logger);
297
+
298
+   /**
299
+    * Creates the bottom drop zone.
300
+    * 
301
+    * @param    {String} dockClassName
302
+    *           The drop zone class.
303
+    * @param    {Number} height
304
+    *           The bottom drop zone height.
305
+    * 
306
+    * @return   {HtmlElement}
307
+    *           The parent element for the bottom drop zone.
308
+    */
309
+   function createBottomDropZone(dockClassName, height)
310
+   {
311
+      var bottom = document.createElement("div");
312
+      bottom.className = dockClassName;
313
+      
314
+      bottom.style["position"] = "fixed";
315
+      
316
+      bottom.style["bottom"]  = "0px";
317
+      
318
+      bottom.style["height"] = height + "px";
319
+      bottom.style["width"]  = "100%";
320
+      return bottom;
321
+   };
322
+   
323
+   /**
324
+    * Creates the right drop zone.
325
+    * 
326
+    * @param    {String} dockClassName
327
+    *           The drop zone class.
328
+    * @param    {Number} width
329
+    *           The right drop zone width.
330
+    * 
331
+    * @return   {HtmlElement}
332
+    *           The parent element for the right drop zone.
333
+    */
334
+   function createRightDropZone(dockClassName, width)
335
+   {
336
+      var right = document.createElement("div");
337
+      right.className = dockClassName;
338
+      right.style["position"] = "fixed";
339
+      
340
+      right.style["right"] = "0px";
341
+      right.style["top"]   = "0px";
342
+      
343
+      right.style["height"] = "100%";
344
+      right.style["width"]  = width + "px";
345
+      return right;
346
+   };
347
+   
348
+   /**
349
+    * Creates the html element for the draggable task bar.
350
+    * 
351
+    * @param    {String} id
352
+    *           The task bar peer element id.
353
+    * 
354
+    * @return   {HtmlElement}
355
+    *           The task bar peer element.
356
+    */
357
+   function createTaskBarPeer(id)
358
+   {
359
+      var peer = document.createElement("div");
360
+      peer.id = id;
361
+      peer.style["position"] = "relative";
362
+      
363
+      peer.style["height"] = "100%";
364
+      peer.style["width"]  = "100%";
365
+      peer.draggable = true;
366
+      return peer;
367
+   };
368
+   
369
+   /**
370
+    * Gets the task bar.
371
+    * 
372
+    * @return   {TaskBar}
373
+    *           The task bar.
374
+    */
375
+   this.getTaskBar = function()
376
+   {
377
+      return taskBar;
378
+   };
379
+   
380
+   
381
+   /**
382
+    * Creates the task bar for the given peer element with the provided background and
383
+    * foreground colors.
384
+    * 
385
+    * @param    {HtmlElement} peer
386
+    *          The task bar peer element.
387
+    * @param    {Array} bg
388
+    *           The background task bar color. It is represented by the 3-elements array
389
+    *           filled with red, green and blue values from 0 to 255.
390
+    * @param    {Array} fg
391
+    *           The foreground task bar color for task icons. It is represented by the 3-elements array
392
+    *           filled with red, green and blue values from 0 to 255.
393
+    * @param    {Object} logger
394
+    *           The p2j global application logger.
395
+    */
396
+   function TaskBar(peer, bg, fg, logger)
397
+   {
398
+      var DRAGGED_OPACITY = 0.3;
399
+      var TOP_PADDING  = 2;
400
+      var LEFT_PADDING = 2;
401
+      var TASK_BAR_TITLE = "Task Bar"; 
402
+      var TASK_ICON_WIDTH  = 40; 
403
+      var TASK_ICON_HEIGHT = 32; 
404
+      
405
+      var SHIFT = 2;
406
+      
407
+      var dragged;
408
+      var canvas = document.createElement('canvas');
409
+      canvas.className="canvas";
410
+      canvas.style["height"] = "100%";
411
+      canvas.style["width"]  = "100%";
412
+      
413
+      peer.appendChild(canvas);
414
+      var ctx = canvas.getContext('2d', {alpha : true});
415
+//      console.log("peer width = " + peer.offsetWidth);
416
+//      console.log("peer height = " + peer.offsetHeight);
417
+      var strokesManager = new LineStrokes();
418
+      var canvasRenderer = new CanvasRenderer(canvas, ctx, strokesManager, logger);
419
+      
420
+      var taskIcons = [];
421
+
422
+      var foreground  = fg;
423
+      var background  = bg;
424
+      
425
+      if (peer)
426
+      {
427
+         /** events fired on the draggable target */
428
+         peer.addEventListener("dragstart", startDragging);
429
+         peer.addEventListener("dragend", dragEnded);
430
+         peer.title = "Test";
431
+         //peer.addEventListener("drag", drag);
432
+      }
433
+      
434
+      /**
435
+       * Layouts task icons according to the current task bar position:
436
+       * vertical or horizontal.
437
+       * 
438
+       * @param    {Number} width
439
+       *           The task bar width in pixels.
440
+       * @param    {Number} height
441
+       *           The task bar height in pixels.
442
+       */
443
+      function doLayout(width, height) {
444
+         canvas.width = width;
445
+         canvas.height = height;
446
+//         console.log("canvas width = " + canvas.width);
447
+//         console.log("canvas height = " + canvas.height);
448
+         
449
+         canvasRenderer.draw3DRect(ctx, 0, 0, width, height, background, true, true);
450
+         var horizontalLayout;
451
+         if (width > height)
452
+         {
453
+            horizontalLayout = true;
454
+         }
455
+         else
456
+         {
457
+            horizontalLayout = false;
458
+         }
459
+         var x = LEFT_PADDING;
460
+         var y = TOP_PADDING;
461
+         for (var i = 0; i < taskIcons.length; i++)
462
+         {
463
+            var taskIcon = taskIcons[i];
464
+            taskIcon.setLocation(x, y);
465
+            taskIcon.draw();
466
+            if (horizontalLayout)
467
+            {
468
+               x += (SHIFT + taskIcon.width);
469
+            }
470
+            else
471
+            {
472
+               y += (SHIFT + taskIcon.height);
473
+            }
474
+         }
475
+      }
476
+      
477
+      /**
478
+       * Draws the task bar on the canvas.
479
+       */
480
+      this.draw = function()
481
+      {
482
+         doLayout(peer.offsetWidth, peer.offsetHeight);
483
+      }
484
+      
485
+      /**
486
+       * Adds new task to the task bar.
487
+       * 
488
+       * @param    {Window} win
489
+       *           The window to be represented by a task in the task bar.
490
+       * 
491
+       * @return   {TaskIcon}
492
+       *           The task icon that represents the target window.
493
+       */
494
+      function addTaskIcon(win)
495
+      {
496
+         var taskIcon = new TaskIcon(win, null, TASK_ICON_WIDTH, TASK_ICON_HEIGHT, foreground);
497
+         taskIcons.push(taskIcon);
498
+         return taskIcon;
499
+      };
500
+      
501
+      /**
502
+       * Sets an icon for the task that represents the target window.
503
+       * 
504
+       * @param    {Number} windowId
505
+       *           The target window id.
506
+       * @param    {Array} iconData
507
+       *           It is the binary icon to set. The pixels array with 4-bytes per a pixel that
508
+       *           are red, green, blue and alpha bytes.
509
+       * 
510
+       * @return   {TaskIcon}
511
+       *           The task that represents the target window.
512
+       */
513
+      function setIconForTask(windowId, iconData)
514
+      {
515
+         var taskIcon = findTaskIcon(windowId);
516
+         taskIcon.iconData = iconData;
517
+         return taskIcon;
518
+      };
519
+      
520
+      this.addTaskIcon    = addTaskIcon;
521
+      this.setIconForTask = setIconForTask;
522
+
523
+      /**
524
+       * Find the window task that represents the target window.
525
+       * 
526
+       * @param    {Number} windowId
527
+       *           The target window id.
528
+       * 
529
+       * @return   {TaskIcon}
530
+       *           The task that represents the target window.
531
+       */
532
+      function findTaskIcon(windowId)
533
+      {
534
+         var taskIcon;
535
+         for (var i = 0; i < taskIcons.length; i++)
536
+         {
537
+            var taskIcon = taskIcons[i];
538
+            if (taskIcon.win.id === windowId)
539
+            {
540
+               break;
541
+            }
542
+         }
543
+         return taskIcon;
544
+      };
545
+      
546
+      /**
547
+       * Collapses the given window. Sets the corresponding task icon to be inactive.
548
+       * 
549
+       * @param    {Number} windowId
550
+       *           The target window id.
551
+       */
552
+      this.iconify = function(windowId)
553
+      {
554
+         var taskIcon = findTaskIcon(windowId);
555
+         if (taskIcon === undefined)
556
+         {
557
+            return;
558
+         }
559
+         taskIcon.setActive(false);
560
+         taskIcon.draw();
561
+      };
562
+
563
+      /**
564
+       * Restores the window. Sets the corresponding task icon to be active.
565
+       * 
566
+       * @param    {Number} windowId
567
+       *           The target window id.
568
+       */
569
+      this.deiconify = function(windowId)
570
+      {
571
+         var taskIcon = findTaskIcon(windowId);
572
+         if (taskIcon === undefined)
573
+         {
574
+            return;
575
+         }
576
+         taskIcon.setActive(true);
577
+         taskIcon.draw();
578
+      };
579
+
580
+      function startDragging(event) {
581
+         event.dataTransfer.setData('text/plain',null);
582
+         dragged = event.target;
583
+         event.target.style.opacity = DRAGGED_OPACITY;
584
+      }
585
+
586
+      function dragEnded(event) {
587
+         event.target.style.opacity = 1;
588
+      }
589
+      
590
+      function drag( event ) {
591
+      }
592
+
593
+      /* events fired on the drop targets */
594
+      document.addEventListener("dragover",
595
+            function( event )
596
+            {
597
+                event.preventDefault();
598
+            }, false);
599
+
600
+      document.addEventListener("dragenter",
601
+            function( event )
602
+            {
603
+               var cls = event.target.className;
604
+                if ( cls.indexOf(DOCK_CLASS_NAME) >= 0) {
605
+                   event.target.style["background"] = getTransparentColor(background, 0.5);;
606
+                }
607
+            }, false);
608
+
609
+      document.addEventListener("dragleave",
610
+            function( event )
611
+            {
612
+               var cls = event.target.className;
613
+                if ( cls.indexOf(DOCK_CLASS_NAME) >= 0 ) {
614
+                   event.target.style["background"] = getTransparentColor(background, 0.0);;
615
+                }
616
+            }, false);
617
+
618
+      document.addEventListener("drop",
619
+            function( event )
620
+            {
621
+                var cls = event.target.className;
622
+                if ( cls.indexOf(DOCK_CLASS_NAME) >= 0) {
623
+                   var parent = dragged.parentNode;
624
+                   parent.removeChild(dragged);
625
+                   try {
626
+                      event.target.appendChild(dragged);
627
+                      parent.style["background"] = getTransparentColor(background, 0.0);
628
+                   }
629
+                   catch(e)
630
+                   {
631
+                      parent.addChild(dragged);
632
+                   }
633
+                   doLayout(peer.offsetWidth, peer.offsetHeight);
634
+                }
635
+                event.preventDefault();
636
+            }, false);
637
+
638
+      /**
639
+       * Returns rgba(r,g,b,a) string representation for the target color
640
+       * with the target transparency.
641
+       * 
642
+       * @param    {Number[]} c
643
+       *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
644
+       * @param    {Number} transparency
645
+       *           The transparency from 0.0 to 1.0.
646
+       * 
647
+       * @return   {String}
648
+       *           The 'rgba(r,g,b,a)' string representation.
649
+       */
650
+      function getTransparentColor(c, transparency)
651
+      {
652
+         var parameters = [];
653
+         Array.prototype.push.apply(parameters, c);
654
+         parameters.push(transparency);
655
+         return "rgba(" + parameters.join() + ")";
656
+      }
657
+      
658
+      /**
659
+       * Creates the task icon widget that represents the target window on the task bar.
660
+       * 
661
+       * @param    {Window} win
662
+       *           The window to be represented by a task in the task bar.
663
+       * @param    {Array} iconData
664
+       *           It is the binary icon to set. The pixels array with 4-bytes per a pixel that
665
+       *           are red, green, blue and alpha bytes.
666
+       * @param    {Number} w
667
+       *           The task icon widget width in pixels.
668
+       * @param    {Number} h
669
+       *           The task icon widget height in pixels.
670
+       * @param    {Number[]} c
671
+       *           The task icon widget color. Array of 3 integer values between 0
672
+       *           and 255 inclusive, representing an RGB color.
673
+       */
674
+      function TaskIcon(win, iconData, w, h, c)
675
+      {
676
+         this.win = win;
677
+         this.iconData = iconData;
678
+         this.width  = w;
679
+         this.height = h;
680
+         this.color  = c;
681
+         var that = this;
682
+         var active = false;
683
+         this.x = 0;
684
+         this.y = 0;
685
+
686
+         this.setLocation = setLocation;
687
+         this.setActive = setActive;
688
+         this.isActive  = isActive;
689
+         this.draw = draw;
690
+
691
+         /**
692
+          * Sets the widget location.
693
+          */
694
+         function setLocation(x, y)
695
+         {
696
+            this.x = x;
697
+            this.y = y;
698
+         };
699
+         
700
+         /**
701
+          * Sets an active state.
702
+          */
703
+         function setActive(value)
704
+         {
705
+            active = value;
706
+         };
707
+         
708
+         /**
709
+          * Is active?
710
+          */
711
+         function isActive()
712
+         {
713
+            return active;
714
+         };
715
+         
716
+         /**
717
+          * Draw the widget on the task bar canvas.
718
+          */
719
+         function draw()
720
+         {
721
+            var c;
722
+            if (active)
723
+            {
724
+               c = canvasRenderer.lightenColor(that.color);
725
+            }
726
+            else
727
+            {
728
+               c = that.color;
729
+            }
730
+            canvasRenderer.draw3DRect(ctx, that.x, that.y, that.width, that.height, c, true, !active);
731
+            if (that.iconData)
732
+            {
733
+               var iconWidth  = that.win.iconWidth;
734
+               var iconHeight = that.win.iconHeight;
735
+               canvasRenderer.drawImage(ctx, that.x, that.y + (that.height - iconHeight) / 2,
736
+                     iconWidth, iconHeight, that.iconData, 0);
737
+            }
738
+         };
739
+         
740
+         /**
741
+          * Tests the mouse pointer inside the widgets bounds.
742
+          */
743
+         function testMousePointerInside(event)
744
+         {
745
+            var rect = peer.getBoundingClientRect();
746
+            var x_rel = event.clientX - rect.left;
747
+            var y_rel = event.clientY - rect.top;
748
+            return isInOrder(that.x, x_rel, that.x + that.width)
749
+                  && isInOrder(that.y, y_rel, that.y + that.height);
750
+         };
751
+         
752
+         /**
753
+          * Returns true iff a <= b <= c
754
+          */
755
+         function isInOrder(a, b, c)
756
+         {
757
+            if (a > b || b > c)
758
+            {
759
+               return false;
760
+            }
761
+            return true;
762
+         };
763
+         
764
+         /**
765
+          * Adds the "on click" widget action. If window is inactive, sets the active state and
766
+          * sends the request to server in order to change the window state.
767
+          */
768
+         peer.addEventListener("click", function(event) {
769
+            if (testMousePointerInside(event) && !that.isActive())
770
+            {
771
+               that.setActive(true);
772
+               if (taskIconOnClickCallback)
773
+               {
774
+                  taskIconOnClickCallback(that.win.id);
775
+               }
776
+               that.draw();
777
+            }
778
+         });
779
+         peer.addEventListener("mouseenter", function(event) {
780
+            if (testMousePointerInside(event))
781
+            {
782
+               peer.title = (that.win.title !== null && that.win.title !== udefined)
783
+                                 ? that.win.title : " ";
784
+            }
785
+         });
786
+//         peer.addEventListener("mouseover", function(event) {
787
+//            if (testMousePointerInside(event))
788
+//            {
789
+//               peer.title = that.win.title;
790
+//            }
791
+//         });
792
+         peer.addEventListener("mouseleave", function(event) {
793
+            if (testMousePointerInside(event))
794
+            {
795
+               peer.title = TASK_BAR_TITLE;
796
+            }
797
+         });
798
+      }
799
+   }
800
+}
801
+
802
+
803