only update affected area of bitmap
[aros:aros.git] / AROS / workbench / c / Decoration / decoration.c
1 /*
2     Copyright  1995-2013, The AROS Development Team.
3     $Id$
4 */
5
6 /******************************************************************************
7
8     NAME
9
10         Decoration
11
12     SYNOPSIS
13
14         (N/A)
15
16     LOCATION
17
18         C:
19
20     FUNCTION
21
22         Allows user definable skins for the intuition windows, menus and gadgets.
23         
24     NOTES
25
26         Must be launched before Wanderer - usually in the S:startup-sequence
27         
28     BUGS
29
30     SEE ALSO
31
32         IPREFS
33         
34     INTERNALS
35
36 ******************************************************************************/
37
38 #define DEBUG 0
39 #include <aros/debug.h>
40
41 #include <clib/alib_protos.h>
42
43 #include <proto/exec.h>
44 #include <proto/dos.h>
45 #include <proto/intuition.h>
46
47 #include <aros/detach.h>
48
49 #include "windowdecorclass.h"
50 #include "screendecorclass.h"
51 #include "menudecorclass.h"
52 #include "newimage.h"
53 #include "config.h"
54
55 const TEXT version_string[] = "$VER: Decoration 1.7 (9.10.2013)";
56
57 STRPTR __detached_name = "Decorator";
58
59 #define MAGIC_PRIVATE_SKIN              0x0001
60 #define MAGIC_PRIVATE_TITLECHILD        0x0F0F
61
62 struct DecorationDecorator
63 {
64     struct NewDecorator base;   /* MUST BE FIRST */
65     struct DecorConfig * dc;
66     struct DecorImages * di;
67 };
68
69 struct  DecorationDecorator *basedecor = NULL;
70
71 struct SkinMessage {
72     struct MagicMessage msg;
73     UWORD  class;
74     STRPTR  path;
75     STRPTR  id;
76 };
77
78 void DeleteDecorator(struct NewDecorator *nd)
79 {
80     if (nd == NULL) return;
81     if (((struct DecorationDecorator *)nd)->dc != NULL) FreeConfig(((struct DecorationDecorator *)nd)->dc);
82     if (((struct DecorationDecorator *)nd)->di != NULL) FreeImages(((struct DecorationDecorator *)nd)->di);
83     FreeVec(nd);
84 }
85
86 struct DecorationDecorator *LoadDecoration(STRPTR path)
87 {
88     struct DecorationDecorator * dnd = NULL;
89     struct TagItem *screenTags, *menuTags, *windowTags;
90
91     D(bug("LoadDecoration: Entering\n"));
92
93     STRPTR newpath;
94
95     if (path != NULL) newpath = path; else newpath = "Theme:";
96
97     dnd = AllocVec(sizeof(struct DecorationDecorator), MEMF_CLEAR | MEMF_ANY);
98     
99     D(bug("LoadDecoration: decorator @ 0x%p\n", dnd));
100
101     if (dnd)
102     {
103         dnd->dc = LoadConfig(newpath);
104         D(bug("LoadDecoration: config @ 0x%p\n", dnd->dc));
105         if (!dnd->dc)
106         {
107             DeleteDecorator(&dnd->base);
108             return NULL;
109         }
110         
111         dnd->di = LoadImages(dnd->dc);
112         D(bug("LoadDecoration: images @ 0x%p\n", dnd->di));
113         if (!dnd->di)
114         {
115             DeleteDecorator(&dnd->base);
116             return NULL;
117         }
118
119         dnd->base.nd_ScreenTags = AllocVec(sizeof(struct TagItem) * 4, MEMF_CLEAR | MEMF_ANY);
120         dnd->base.nd_MenuTags = AllocVec(sizeof(struct TagItem) * 4, MEMF_CLEAR | MEMF_ANY);       
121         dnd->base.nd_WindowTags = AllocVec(sizeof(struct TagItem) * 4, MEMF_CLEAR | MEMF_ANY);
122
123         if (basedecor)
124         {
125             D(bug("LoadDecoration: copying base classes\n"));
126             dnd->base.nd_ScreenClass = basedecor->base.nd_ScreenClass;
127             dnd->base.nd_MenuClass = basedecor->base.nd_MenuClass;
128             dnd->base.nd_WindowClass = basedecor->base.nd_WindowClass;
129         }
130
131         screenTags = dnd->base.nd_ScreenTags;
132         menuTags = dnd->base.nd_MenuTags;
133         windowTags = dnd->base.nd_WindowTags;
134
135         screenTags[0].ti_Tag = SDA_UserBuffer;
136         menuTags[0].ti_Tag = MDA_UserBuffer;
137         windowTags[0].ti_Tag = WDA_UserBuffer;
138         screenTags[0].ti_Data = sizeof(struct ScreenData);
139         menuTags[0].ti_Data = sizeof(struct MenuData);
140         windowTags[0].ti_Data = sizeof(struct WindowData);
141
142         screenTags[1].ti_Tag = SDA_DecorImages;
143         menuTags[1].ti_Tag = MDA_DecorImages;
144         windowTags[1].ti_Tag = WDA_DecorImages;
145         screenTags[1].ti_Data = (IPTR)dnd->di;
146         menuTags[1].ti_Data = (IPTR)dnd->di;
147         windowTags[1].ti_Data = (IPTR)dnd->di;
148
149         screenTags[2].ti_Tag =  SDA_DecorConfig;
150         menuTags[2].ti_Tag = MDA_DecorConfig;
151         windowTags[2].ti_Tag = WDA_DecorConfig;
152         screenTags[2].ti_Data = (IPTR)dnd->dc;
153         menuTags[2].ti_Data = (IPTR)dnd->dc;
154         windowTags[2].ti_Data = (IPTR)dnd->dc;
155         
156         screenTags[3].ti_Tag = TAG_DONE;
157         menuTags[3].ti_Tag = TAG_DONE;
158         windowTags[3].ti_Tag = TAG_DONE;
159
160     }
161     return dnd;
162 }
163
164 #define ARGUMENT_TEMPLATE "PATH,SCREENID=ID/K"
165
166 char usage[] =
167     "Decoration:\n"
168     "Arguments:\n";
169
170 int main(void)
171 {
172     struct  NewDecorator *decor;
173     struct MsgPort *port;
174
175     IPTR rd_Args[] = {0, 0, };
176
177     struct RDArgs *args, *newargs;
178
179     /* the 1M $$ Question why "Decoration ?" does not work in the shell? */
180
181     newargs = (struct RDArgs*) AllocDosObject(DOS_RDARGS, NULL);
182
183     if (newargs == NULL) return 0;
184
185     newargs->RDA_ExtHelp = usage;
186     newargs->RDA_Flags = 0;
187     
188     args = ReadArgs(ARGUMENT_TEMPLATE, rd_Args, newargs);
189
190     if (args == NULL) {
191         FreeDosObject (DOS_RDARGS, (APTR) newargs);
192         return 0;
193     }
194
195     if ((port = CreateMsgPort()) == NULL)
196         return 0;
197
198     Forbid();
199     if (FindPort(__detached_name)) {
200         struct SkinMessage msg;
201         msg.msg.mn_ReplyPort = port;
202         msg.msg.mn_Magic = MAGIC_PRIVATE_SKIN;
203         msg.class = 0;
204         msg.path = (STRPTR) rd_Args[0];
205         msg.id = (STRPTR) rd_Args[1];
206         PutMsg(FindPort(__detached_name), (struct Message *) &msg);
207         WaitPort(port);
208         GetMsg(port);
209         Permit();
210         DeleteMsgPort(port);
211         FreeArgs(args);
212         return 0;
213     }
214     Permit();
215
216     D(bug("Decoration: making classes...\n"));
217
218     if ((basedecor = LoadDecoration((STRPTR) rd_Args[0])) != NULL)
219     {
220         decor = &basedecor->base;
221         if ((basedecor->base.nd_ScreenClass = MakeScreenDecorClass()) != NULL)
222         {
223             if ((basedecor->base.nd_MenuClass = MakeMenuDecorClass()) != NULL)
224             {
225                 if ((basedecor->base.nd_WindowClass = MakeWindowDecorClass()) != NULL)
226                 {
227                     D(bug("Decoration: Classes made (screen @ 0x%p, menu @ 0x%p, win @ 0x%p)\n", basedecor->base.nd_ScreenClass, basedecor->base.nd_MenuClass, basedecor->base.nd_WindowClass));
228
229                     ULONG  skinSignal = 1 << port->mp_SigBit;
230                     port->mp_Node.ln_Name=__detached_name;
231                     AddPort(port);
232
233                     D(bug("Decoration: Port created and added\n"));
234
235                     D(bug("Decoration: Got decorator\n"));
236
237                     if (decor != NULL)
238                     {
239                         decor->nd_Pattern = (STRPTR) rd_Args[1];
240                         decor->nd_Port = port;
241                         ChangeDecoration(DECORATION_SET, decor);
242                     }
243
244                     D(bug("Before Detach()\n"));
245
246                     Detach();
247
248                     D(bug("After Detach()\n"));
249
250                     BOOL running = TRUE;
251
252                     while (running)
253                     {
254                         ULONG sigs = Wait(SIGBREAKF_CTRL_C | skinSignal);
255                         if ((sigs & SIGBREAKF_CTRL_C) != 0)
256                         {
257                             //       running = FALSE; /* at the moment no exit */
258                         }
259                         else if ((sigs & skinSignal) != 0)
260                         {
261                             struct DecoratorMessage *dmsg;
262                             struct SkinMessage * msg = (struct SkinMessage *) GetMsg(port);
263                             while (msg)
264                             {
265                                 switch(msg->msg.mn_Magic)
266                                 {
267                                     case MAGIC_PRIVATE_TITLECHILD:
268                                         dmsg = (struct DecoratorMessage *) msg;
269                                         if (decor)
270                                         {
271                                             SetAttrs((Object *)*((Object **)((IPTR)dmsg->dm_Class + (IPTR)decor->nd_ScreenObjOffset)), SDA_TitleChild, dmsg->dm_Object, TAG_DONE);
272                                         }
273                                         break;
274                                     case MAGIC_PRIVATE_SKIN:
275                                         decor = (struct NewDecorator *)LoadDecoration(msg->path);
276                                         if (decor != NULL)
277                                         {
278                                             decor->nd_Pattern = msg->id;
279                                             decor->nd_Port = port;
280                                             ChangeDecoration(DECORATION_SET, decor);
281                                         }
282                                         break;
283                                     case MAGIC_DECORATOR:
284                                         dmsg = (struct DecoratorMessage *) msg;
285                                         DeleteDecorator((struct NewDecorator *) dmsg->dm_Object);
286                                         break;
287                                 }
288                                 ReplyMsg((struct Message *) msg);
289                                 msg = (struct SkinMessage *) GetMsg(port);
290                             }
291                         }
292                     }
293                     FreeClass(decor->nd_WindowClass);
294                 }
295                 FreeClass(decor->nd_MenuClass);
296             }
297             FreeClass(decor->nd_ScreenClass);
298         }
299     }
300     FreeDosObject (DOS_RDARGS, (APTR) newargs);
301     FreeArgs(args);
302     return 0;
303 }