~ubuntu-branches/ubuntu/precise/clutter-1.0/precise

« back to all changes in this revision

Viewing changes to clutter/x11/clutter-stage-x11.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 * Lesser General Public License for more details.
15
15
 *
16
16
 * You should have received a copy of the GNU Lesser General Public
17
 
 * License along with this library; if not, write to the
18
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
 
 * Boston, MA 02111-1307, USA.
 
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
18
 *
 
19
 *
20
20
 */
21
21
 
22
22
#ifdef HAVE_CONFIG_H
23
23
#include "config.h"
24
24
#endif
25
25
 
 
26
#ifdef HAVE_UNISTD_H
 
27
#include <unistd.h>
 
28
#endif
 
29
 
26
30
#include "clutter-backend-x11.h"
27
31
#include "clutter-stage-x11.h"
28
32
#include "clutter-x11.h"
50
54
 
51
55
G_DEFINE_TYPE_WITH_CODE (ClutterStageX11,
52
56
                         clutter_stage_x11,
53
 
                         CLUTTER_TYPE_GROUP,
 
57
                         G_TYPE_OBJECT,
54
58
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
55
59
                                                clutter_stage_window_iface_init));
56
60
 
66
70
{
67
71
  XClientMessageEvent xclient;
68
72
 
 
73
  CLUTTER_NOTE (BACKEND, "%s NET_WM state", add ? "adding" : "removing");
 
74
 
69
75
  memset (&xclient, 0, sizeof (xclient));
70
76
 
71
77
  xclient.type         = ClientMessage;
91
97
                                   gint             new_width,
92
98
                                   gint             new_height)
93
99
{
 
100
  ClutterBackend *backend = clutter_get_default_backend ();
 
101
  ClutterBackendX11 *backend_x11;
94
102
  gboolean resize;
95
103
 
 
104
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
105
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
106
 
96
107
  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
97
108
 
98
 
  if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE)
 
109
  if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin)
99
110
    {
 
111
      guint min_width, min_height;
100
112
      XSizeHints *size_hints;
101
 
      gfloat min_width, min_height;
102
113
 
103
114
      size_hints = XAllocSizeHints();
104
115
 
105
 
      if (new_width < 0)
106
 
        clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11),
107
 
                                           -1,
108
 
                                           &min_width, NULL);
109
 
      else
110
 
        min_width = new_width;
111
 
 
112
 
      if (new_height < 0)
113
 
        clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11),
114
 
                                            min_width,
115
 
                                            &min_height, NULL);
116
 
      else
117
 
        min_height = new_height;
 
116
      clutter_stage_get_minimum_size (stage_x11->wrapper,
 
117
                                      &min_width,
 
118
                                      &min_height);
 
119
 
 
120
      if (new_width <= 0)
 
121
        new_width = min_width;
 
122
 
 
123
      if (new_height <= 0)
 
124
        new_height = min_height;
118
125
 
119
126
      size_hints->flags = 0;
120
127
 
121
128
      /* If we are going fullscreen then we don't want any
122
129
         restrictions on the window size */
123
 
      if (!stage_x11->fullscreen_on_map)
 
130
      if (!stage_x11->fullscreening)
124
131
        {
125
 
          size_hints->min_width = (int) min_width;
126
 
          size_hints->min_height = (int) min_height;
127
 
          size_hints->flags = PMinSize;
128
 
 
129
 
          if (!resize)
130
 
            {
131
 
              size_hints->max_width = size_hints->min_width;
132
 
              size_hints->max_height = size_hints->min_height;
133
 
              size_hints->flags |= PMaxSize;
 
132
          if (resize)
 
133
            {
 
134
              size_hints->min_width = min_width;
 
135
              size_hints->min_height = min_height;
 
136
              size_hints->flags = PMinSize;
 
137
            }
 
138
          else
 
139
            {
 
140
              size_hints->min_width = new_width;
 
141
              size_hints->min_height = new_height;
 
142
              size_hints->max_width = new_width;
 
143
              size_hints->max_height = new_height;
 
144
              size_hints->flags = PMinSize | PMaxSize;
134
145
            }
135
146
        }
136
147
 
137
 
      XSetWMNormalHints (stage_x11->xdpy, stage_x11->xwin, size_hints);
 
148
      XSetWMNormalHints (backend_x11->xdpy, stage_x11->xwin, size_hints);
138
149
 
139
150
      XFree(size_hints);
140
151
    }
143
154
void
144
155
clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11)
145
156
{
146
 
  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
157
  ClutterBackend *backend = clutter_get_default_backend ();
 
158
  ClutterBackendX11 *backend_x11;
147
159
  Atom protocols[2];
148
160
  int n = 0;
149
161
  
 
162
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
163
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
164
 
150
165
  protocols[n++] = backend_x11->atom_WM_DELETE_WINDOW;
151
166
  protocols[n++] = backend_x11->atom_NET_WM_PING;
152
167
 
153
 
  XSetWMProtocols (stage_x11->xdpy, stage_x11->xwin, protocols, n);
154
 
}
155
 
 
156
 
static void
157
 
clutter_stage_x11_get_preferred_width (ClutterActor *self,
158
 
                                       gfloat        for_height,
159
 
                                       gfloat       *min_width_p,
160
 
                                       gfloat       *natural_width_p)
161
 
{
162
 
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
163
 
  gboolean is_fullscreen, resize;
164
 
 
165
 
  is_fullscreen = FALSE;
166
 
  g_object_get (G_OBJECT (stage_x11->wrapper),
167
 
                "fullscreen-set", &is_fullscreen,
168
 
                NULL);
169
 
 
170
 
  if (is_fullscreen || stage_x11->fullscreen_on_map)
171
 
    {
172
 
      int width;
173
 
 
174
 
      width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
175
 
 
176
 
      if (min_width_p)
177
 
        *min_width_p = width;
178
 
 
179
 
      if (natural_width_p)
180
 
        *natural_width_p = width;
181
 
 
182
 
      return;
183
 
    }
184
 
 
185
 
  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
186
 
 
187
 
  if (min_width_p)
188
 
    {
189
 
      if (resize)
190
 
        *min_width_p = 1; /* FIXME need API to set this */
191
 
      else
192
 
        *min_width_p = stage_x11->xwin_width;
193
 
    }
194
 
 
195
 
  if (natural_width_p)
196
 
    *natural_width_p = stage_x11->xwin_width;
197
 
}
198
 
 
199
 
static void
200
 
clutter_stage_x11_get_preferred_height (ClutterActor *self,
201
 
                                        gfloat        for_width,
202
 
                                        gfloat       *min_height_p,
203
 
                                        gfloat       *natural_height_p)
204
 
{
205
 
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
206
 
  gboolean is_fullscreen, resize;
207
 
 
208
 
  is_fullscreen = FALSE;
209
 
  g_object_get (G_OBJECT (stage_x11->wrapper),
210
 
                "fullscreen-set", &is_fullscreen,
211
 
                NULL);
212
 
 
213
 
  if (is_fullscreen || stage_x11->fullscreen_on_map)
214
 
    {
215
 
      int height;
216
 
 
217
 
      height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
218
 
 
219
 
      if (min_height_p)
220
 
        *min_height_p = height;
221
 
 
222
 
      if (natural_height_p)
223
 
        *natural_height_p = height;
224
 
 
225
 
      return;
226
 
    }
227
 
 
228
 
  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
229
 
 
230
 
  if (min_height_p)
231
 
    {
232
 
      if (resize)
233
 
        *min_height_p = 1; /* FIXME need API to set this */
234
 
      else
235
 
        *min_height_p = stage_x11->xwin_height;
236
 
    }
237
 
 
238
 
  if (natural_height_p)
239
 
    *natural_height_p = stage_x11->xwin_height;
240
 
}
241
 
 
242
 
static void
243
 
clutter_stage_x11_allocate (ClutterActor           *self,
244
 
                            const ClutterActorBox  *box,
245
 
                            ClutterAllocationFlags  flags)
246
 
{
247
 
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
248
 
  ClutterActorClass *parent_class;
249
 
  gint new_width, new_height;
250
 
 
251
 
  new_width  = ABS ((int) (box->x2 - box->x1));
252
 
  new_height = ABS ((int) (box->y2 - box->y1));
253
 
 
254
 
  if (new_width == 0 || new_height == 0)
 
168
  XSetWMProtocols (backend_x11->xdpy, stage_x11->xwin, protocols, n);
 
169
}
 
170
 
 
171
static void
 
172
clutter_stage_x11_get_geometry (ClutterStageWindow *stage_window,
 
173
                                ClutterGeometry    *geometry)
 
174
{
 
175
  ClutterBackend *backend = clutter_get_default_backend ();
 
176
  ClutterBackendX11 *backend_x11;
 
177
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
178
 
 
179
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
180
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
181
 
 
182
  /* If we're fullscreen, return the size of the display. */
 
183
  if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) &&
 
184
      stage_x11->fullscreening)
 
185
    {
 
186
      geometry->width = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num);
 
187
      geometry->height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num);
 
188
 
 
189
      return;
 
190
    }
 
191
 
 
192
  geometry->width = stage_x11->xwin_width;
 
193
  geometry->height = stage_x11->xwin_height;
 
194
}
 
195
 
 
196
static void
 
197
clutter_stage_x11_resize (ClutterStageWindow *stage_window,
 
198
                          gint                width,
 
199
                          gint                height)
 
200
{
 
201
  ClutterBackend *backend = clutter_get_default_backend ();
 
202
  ClutterBackendX11 *backend_x11;
 
203
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
204
  ClutterStage *stage = stage_x11->wrapper;
 
205
  gboolean resize;
 
206
 
 
207
  if (stage_x11->is_foreign_xwin)
 
208
    {
 
209
      /* If this is a foreign window we won't get a ConfigureNotify,
 
210
       * so we need to manually set the size and queue a relayout on the
 
211
       * stage here (as is normally done in response to ConfigureNotify).
 
212
       */
 
213
      stage_x11->xwin_width = width;
 
214
      stage_x11->xwin_height = height;
 
215
      clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper));
 
216
      return;
 
217
    }
 
218
 
 
219
  /* If we're going fullscreen, don't mess with the size */
 
220
  if (stage_x11->fullscreening)
 
221
    return;
 
222
 
 
223
  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
 
224
 
 
225
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
226
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
227
 
 
228
  if (width == 0 || height == 0)
255
229
    {
256
230
      /* Should not happen, if this turns up we need to debug it and
257
231
       * determine the cleanest way to fix.
258
232
       */
259
233
      g_warning ("X11 stage not allowed to have 0 width or height");
260
 
      new_width = 1;
261
 
      new_height = 1;
 
234
      width = 1;
 
235
      height = 1;
262
236
    }
263
237
 
264
 
  CLUTTER_NOTE (BACKEND, "New allocation received: (%d, %d)",
265
 
                new_width,
266
 
                new_height);
 
238
  CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height);
267
239
 
268
 
  if (new_width != stage_x11->xwin_width ||
269
 
      new_height != stage_x11->xwin_height)
 
240
  if (stage_x11->xwin != None)
270
241
    {
271
 
      stage_x11->xwin_width  = new_width;
272
 
      stage_x11->xwin_height = new_height;
 
242
      clutter_stage_x11_fix_window_size (stage_x11, width, height);
273
243
 
274
 
      if (stage_x11->xwin != None &&
275
 
          !stage_x11->is_foreign_xwin)
 
244
      if (width != stage_x11->xwin_width ||
 
245
          height != stage_x11->xwin_height)
276
246
        {
277
247
          CLUTTER_NOTE (BACKEND, "%s: XResizeWindow[%x] (%d, %d)",
278
248
                        G_STRLOC,
279
249
                        (unsigned int) stage_x11->xwin,
280
 
                        stage_x11->xwin_width,
281
 
                        stage_x11->xwin_height);
 
250
                        width,
 
251
                        height);
282
252
 
283
253
          CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper,
284
254
                                     CLUTTER_STAGE_IN_RESIZE);
285
255
 
286
 
          XResizeWindow (stage_x11->xdpy,
 
256
          XResizeWindow (backend_x11->xdpy,
287
257
                         stage_x11->xwin,
288
 
                         stage_x11->xwin_width,
289
 
                         stage_x11->xwin_height);
290
 
        }
291
 
 
292
 
      clutter_stage_x11_fix_window_size (stage_x11, new_width, new_height);
293
 
 
294
 
      if (stage_x11->xpixmap != None)
295
 
        {
296
 
          /* Need to recreate to resize */
297
 
          _clutter_actor_rerealize (self, NULL, NULL);
 
258
                         width,
 
259
                         height);
 
260
 
 
261
          /* If the viewport hasn't previously been initialized then even
 
262
           * though we can't guarantee that the server will honour our request
 
263
           * we need to ensure a valid viewport is set before our first paint.
 
264
           */
 
265
          if (G_UNLIKELY (!stage_x11->viewport_initialized))
 
266
            {
 
267
              ClutterPerspective perspective;
 
268
              clutter_stage_get_perspective (stage, &perspective);
 
269
              _cogl_setup_viewport (width,
 
270
                                    height,
 
271
                                    perspective.fovy,
 
272
                                    perspective.aspect,
 
273
                                    perspective.z_near,
 
274
                                    perspective.z_far);
 
275
            }
298
276
        }
299
277
    }
300
 
 
301
 
  /* chain up to fill in actor->priv->allocation */
302
 
  parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class);
303
 
  parent_class->allocate (self, box, flags);
304
278
}
305
279
 
306
280
static inline void
307
281
set_wm_pid (ClutterStageX11 *stage_x11)
308
282
{
309
 
  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
283
  ClutterBackend *backend = clutter_get_default_backend ();
 
284
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
310
285
  long pid;
311
286
 
312
 
  if (stage_x11->xwin == None)
 
287
  if (stage_x11->xwin == None || stage_x11->is_foreign_xwin)
313
288
    return;
314
289
 
315
290
  /* this will take care of WM_CLIENT_MACHINE and WM_LOCALE_NAME */
316
 
  XSetWMProperties (stage_x11->xdpy, stage_x11->xwin,
 
291
  XSetWMProperties (backend_x11->xdpy, stage_x11->xwin,
317
292
                    NULL,
318
293
                    NULL,
319
294
                    NULL, 0,
320
295
                    NULL, NULL, NULL);
321
296
 
322
 
  pid = getpid();
323
 
  XChangeProperty (stage_x11->xdpy,
 
297
  pid = getpid ();
 
298
  XChangeProperty (backend_x11->xdpy,
324
299
                   stage_x11->xwin,
325
300
                   backend_x11->atom_NET_WM_PID, XA_CARDINAL, 32,
326
301
                   PropModeReplace,
330
305
static inline void
331
306
set_wm_title (ClutterStageX11 *stage_x11)
332
307
{
333
 
  ClutterBackendX11 *backend_x11 = stage_x11->backend;
334
 
 
335
 
  if (stage_x11->xwin == None)
 
308
  ClutterBackend *backend = clutter_get_default_backend ();
 
309
  ClutterBackendX11 *backend_x11;
 
310
 
 
311
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
312
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
313
 
 
314
  if (stage_x11->xwin == None || stage_x11->is_foreign_xwin)
336
315
    return;
337
316
 
338
317
  if (stage_x11->title == NULL)
339
318
    {
340
 
      XDeleteProperty (stage_x11->xdpy, 
 
319
      XDeleteProperty (backend_x11->xdpy,
341
320
                       stage_x11->xwin, 
342
321
                       backend_x11->atom_NET_WM_NAME);
343
322
    }
344
323
  else
345
324
    {
346
 
      XChangeProperty (stage_x11->xdpy, 
 
325
      XChangeProperty (backend_x11->xdpy,
347
326
                       stage_x11->xwin, 
348
 
                       backend_x11->atom_NET_WM_NAME, 
349
 
                       backend_x11->atom_UTF8_STRING, 
 
327
                       backend_x11->atom_NET_WM_NAME,
 
328
                       backend_x11->atom_UTF8_STRING,
350
329
                       8, 
351
330
                       PropModeReplace, 
352
 
                       (unsigned char *) stage_x11->title, 
 
331
                       (unsigned char *) stage_x11->title,
353
332
                       (int) strlen (stage_x11->title));
354
333
    }
355
334
}
357
336
static inline void
358
337
set_cursor_visible (ClutterStageX11 *stage_x11)
359
338
{
 
339
  ClutterBackend *backend = clutter_get_default_backend ();
 
340
  ClutterBackendX11 *backend_x11;
 
341
 
 
342
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
343
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
344
 
360
345
  if (stage_x11->xwin == None)
361
346
    return;
362
347
 
367
352
  if (stage_x11->is_cursor_visible)
368
353
    {
369
354
#if 0 /* HAVE_XFIXES - seems buggy/unreliable */
370
 
      XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
 
355
      XFixesShowCursor (backend_x11->xdpy, stage_x11->xwin);
371
356
#else
372
 
      XUndefineCursor (stage_x11->xdpy, stage_x11->xwin);
 
357
      XUndefineCursor (backend_x11->xdpy, stage_x11->xwin);
373
358
#endif /* HAVE_XFIXES */
374
359
    }
375
360
  else
377
362
#if 0 /* HAVE_XFIXES - seems buggy/unreliable, check cursor in firefox 
378
363
       *               loading page after hiding.  
379
364
      */
380
 
      XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
 
365
      XFixesHideCursor (backend_x11->xdpy, stage_x11->xwin);
381
366
#else
382
367
      XColor col;
383
368
      Pixmap pix;
384
369
      Cursor curs;
385
370
 
386
 
      pix = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin, 1, 1, 1);
 
371
      pix = XCreatePixmap (backend_x11->xdpy, stage_x11->xwin, 1, 1, 1);
387
372
      memset (&col, 0, sizeof (col));
388
 
      curs = XCreatePixmapCursor (stage_x11->xdpy, 
 
373
      curs = XCreatePixmapCursor (backend_x11->xdpy,
389
374
                                  pix, pix,
390
375
                                  &col, &col,
391
376
                                  1, 1);
392
 
      XFreePixmap (stage_x11->xdpy, pix);
393
 
      XDefineCursor (stage_x11->xdpy, stage_x11->xwin, curs);
 
377
      XFreePixmap (backend_x11->xdpy, pix);
 
378
      XDefineCursor (backend_x11->xdpy, stage_x11->xwin, curs);
394
379
#endif /* HAVE_XFIXES */
395
380
    }
396
381
}
397
382
 
398
 
static void
399
 
clutter_stage_x11_realize (ClutterActor *actor)
 
383
static gboolean
 
384
clutter_stage_x11_realize (ClutterStageWindow *stage_window)
400
385
{
401
 
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
 
386
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
402
387
 
403
388
  set_wm_pid (stage_x11);
404
389
  set_wm_title (stage_x11);
405
390
  set_cursor_visible (stage_x11);
 
391
 
 
392
  return TRUE;
406
393
}
407
394
 
408
395
static void
409
396
clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
410
397
                                  gboolean            is_fullscreen)
411
398
{
 
399
  ClutterBackend *backend = clutter_get_default_backend ();
 
400
  ClutterBackendX11 *backend_x11;
412
401
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
413
 
  ClutterBackendX11 *backend_x11 = stage_x11->backend;
414
402
  ClutterStage *stage = stage_x11->wrapper;
415
403
 
 
404
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
405
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
406
 
416
407
  if (stage == NULL)
417
408
    return;
418
409
 
 
410
  if (!!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) == is_fullscreen)
 
411
    return;
 
412
 
 
413
  CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");
 
414
 
419
415
  CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
420
416
 
421
417
  if (is_fullscreen)
427
423
         but Metacity (at least) will fullscreen to only one of the
428
424
         displays. This will cause the actor to report the wrong size
429
425
         until the ConfigureNotify for the correct size is received */
430
 
      width  = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
431
 
      height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
432
 
 
433
 
      /* we force the stage to the screen size here, in order to
434
 
       * get the fullscreen stage size right after the call to
435
 
       * clutter_stage_fullscreen(). XXX this might break in case
436
 
       * the stage is not fullscreened, but if that does not happen
437
 
       * we are massively screwed anyway
438
 
       */
439
 
      stage_x11->xwin_width = width;
440
 
      stage_x11->xwin_height = height;
441
 
 
442
 
      if (!STAGE_X11_IS_MAPPED (stage_x11))
443
 
        stage_x11->fullscreen_on_map = TRUE;
 
426
      width  = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num);
 
427
      height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num);
 
428
 
 
429
      /* Set the fullscreen hint so we can retain the old size of the window. */
 
430
      stage_x11->fullscreening = TRUE;
444
431
 
445
432
      if (stage_x11->xwin != None)
446
433
        {
449
436
           * a resize when calling clutter_stage_fullscreen() before showing
450
437
           * the stage
451
438
           */
452
 
          if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
 
439
          if (!/*CLUTTER_ACTOR_IS_MAPPED (stage_x11->wrapper)*/ STAGE_X11_IS_MAPPED (stage_x11))
453
440
            {
 
441
              CLUTTER_NOTE (BACKEND, "Fullscreening unmapped stage");
 
442
 
454
443
              /* FIXME: This wont work if we support more states */
455
 
              XChangeProperty (stage_x11->xdpy,
 
444
              XChangeProperty (backend_x11->xdpy,
456
445
                               stage_x11->xwin,
457
446
                               backend_x11->atom_NET_WM_STATE, XA_ATOM, 32,
458
447
                               PropModeReplace,
460
449
            }
461
450
          else
462
451
            {
 
452
              CLUTTER_NOTE (BACKEND, "Fullscreening mapped stage");
 
453
 
463
454
              /* We need to fix the window size so that it will remove
464
455
                 the maximum and minimum window hints. Otherwise
465
456
                 metacity will honour the restrictions and not
474
465
    }
475
466
  else
476
467
    {
477
 
      if (!STAGE_X11_IS_MAPPED (stage_x11))
478
 
        stage_x11->fullscreen_on_map = FALSE;
 
468
      stage_x11->fullscreening = FALSE;
479
469
 
480
470
      if (stage_x11->xwin != None)
481
471
        {
482
 
          if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
 
472
          if (!/*CLUTTER_ACTOR_IS_MAPPED (stage_x11->wrapper)*/ STAGE_X11_IS_MAPPED (stage_x11))
483
473
            {
 
474
              CLUTTER_NOTE (BACKEND, "Un-fullscreening unmapped stage");
 
475
 
484
476
              /* FIXME: This wont work if we support more states */
485
 
              XDeleteProperty (stage_x11->xdpy, 
 
477
              XDeleteProperty (backend_x11->xdpy,
486
478
                               stage_x11->xwin, 
487
479
                               backend_x11->atom_NET_WM_STATE);
488
480
            }
489
481
          else
490
482
            {
 
483
              CLUTTER_NOTE (BACKEND, "Un-fullscreening mapped stage");
 
484
 
491
485
              send_wmspec_change_state (backend_x11,
492
486
                                        stage_x11->xwin,
493
487
                                        backend_x11->atom_NET_WM_STATE_FULLSCREEN,
495
489
 
496
490
              /* Fix the window size to restore the minimum/maximum
497
491
                 restriction */
498
 
              clutter_stage_x11_fix_window_size (stage_x11, -1, -1);
 
492
              clutter_stage_x11_fix_window_size (stage_x11,
 
493
                                                 stage_x11->xwin_width,
 
494
                                                 stage_x11->xwin_height);
499
495
            }
500
496
        }
501
497
    }
531
527
{
532
528
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
533
529
 
534
 
  clutter_stage_x11_fix_window_size (stage_x11, -1, -1);
 
530
  clutter_stage_x11_fix_window_size (stage_x11,
 
531
                                     stage_x11->xwin_width,
 
532
                                     stage_x11->xwin_height);
535
533
}
536
534
 
537
535
static void
538
536
update_wm_hints (ClutterStageX11 *stage_x11)
539
537
{
 
538
  ClutterBackend *backend;
 
539
  ClutterBackendX11 *backend_x11;
540
540
  XWMHints wm_hints;
541
541
 
542
542
  if (stage_x11->wm_state & STAGE_X11_WITHDRAWN)
543
543
    return;
544
544
 
 
545
  if (stage_x11->is_foreign_xwin)
 
546
    return;
 
547
 
 
548
  backend = clutter_get_default_backend ();
 
549
 
 
550
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
551
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
552
 
545
553
  wm_hints.flags = StateHint;
546
554
  wm_hints.initial_state = NormalState;
547
555
 
548
 
  XSetWMHints (stage_x11->xdpy, stage_x11->xwin, &wm_hints);
 
556
  XSetWMHints (backend_x11->xdpy, stage_x11->xwin, &wm_hints);
549
557
}
550
558
 
551
559
static void
571
579
clutter_stage_x11_show (ClutterStageWindow *stage_window,
572
580
                        gboolean            do_raise)
573
581
{
 
582
  ClutterBackend *backend = clutter_get_default_backend ();
 
583
  ClutterBackendX11 *backend_x11;
574
584
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
575
585
 
 
586
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
587
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
588
 
576
589
  if (stage_x11->xwin != None)
577
590
    {
578
 
      if (do_raise)
 
591
      if (do_raise && !stage_x11->is_foreign_xwin)
579
592
        {
580
593
          CLUTTER_NOTE (BACKEND, "Raising stage[%lu]",
581
594
                        (unsigned long) stage_x11->xwin);
582
 
          XRaiseWindow (stage_x11->xdpy, stage_x11->xwin);
 
595
          XRaiseWindow (backend_x11->xdpy, stage_x11->xwin);
583
596
        }
584
597
 
585
598
      if (!STAGE_X11_IS_MAPPED (stage_x11))
587
600
          CLUTTER_NOTE (BACKEND, "Mapping stage[%lu]",
588
601
                        (unsigned long) stage_x11->xwin);
589
602
 
590
 
          if (stage_x11->fullscreen_on_map)
 
603
          set_stage_state (stage_x11, STAGE_X11_WITHDRAWN, 0);
 
604
 
 
605
          update_wm_hints (stage_x11);
 
606
 
 
607
          if (stage_x11->fullscreening)
591
608
            clutter_stage_x11_set_fullscreen (stage_window, TRUE);
592
609
          else
593
610
            clutter_stage_x11_set_fullscreen (stage_window, FALSE);
594
 
 
595
 
          set_stage_state (stage_x11, STAGE_X11_WITHDRAWN, 0);
596
 
 
597
 
          update_wm_hints (stage_x11);
598
611
        }
599
612
 
600
613
      g_assert (STAGE_X11_IS_MAPPED (stage_x11));
601
614
 
602
 
      clutter_actor_map (CLUTTER_ACTOR (stage_x11));
603
615
      clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper));
604
616
 
605
 
      /* we force a redraw here, so that by the time we have
606
 
       * been mapped, the window has contents
607
 
       */
608
 
      _clutter_do_redraw (CLUTTER_STAGE (stage_x11->wrapper));
609
 
 
610
 
      XMapWindow (stage_x11->xdpy, stage_x11->xwin);
 
617
      if (!stage_x11->is_foreign_xwin)
 
618
        XMapWindow (backend_x11->xdpy, stage_x11->xwin);
611
619
    }
612
620
}
613
621
 
614
622
static void
615
623
clutter_stage_x11_hide (ClutterStageWindow *stage_window)
616
624
{
 
625
  ClutterBackend *backend = clutter_get_default_backend ();
 
626
  ClutterBackendX11 *backend_x11;
617
627
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
618
628
 
 
629
  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
 
630
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
631
 
619
632
  if (stage_x11->xwin != None)
620
633
    {
621
634
      if (STAGE_X11_IS_MAPPED (stage_x11))
623
636
 
624
637
      g_assert (!STAGE_X11_IS_MAPPED (stage_x11));
625
638
 
626
 
      clutter_actor_unmap (CLUTTER_ACTOR (stage_x11));
627
639
      clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper));
628
640
 
629
 
      XWithdrawWindow (stage_x11->xdpy,
630
 
                       stage_x11->xwin,
631
 
                       0);
 
641
      if (!stage_x11->is_foreign_xwin)
 
642
        XWithdrawWindow (backend_x11->xdpy, stage_x11->xwin, 0);
632
643
    }
633
644
}
634
645
 
658
669
clutter_stage_x11_class_init (ClutterStageX11Class *klass)
659
670
{
660
671
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
661
 
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
662
672
 
663
673
  gobject_class->finalize = clutter_stage_x11_finalize;
664
674
  gobject_class->dispose = clutter_stage_x11_dispose;
665
 
 
666
 
  actor_class->realize = clutter_stage_x11_realize;
667
 
 
668
 
  actor_class->get_preferred_width = clutter_stage_x11_get_preferred_width;
669
 
  actor_class->get_preferred_height = clutter_stage_x11_get_preferred_height;
670
 
  actor_class->allocate = clutter_stage_x11_allocate;
671
675
}
672
676
 
673
677
static void
674
678
clutter_stage_x11_init (ClutterStageX11 *stage)
675
679
{
676
 
  stage->xdpy = NULL;
677
 
  stage->xwin_root = None;
678
 
  stage->xscreen = 0;
679
 
 
680
680
  stage->xwin = None;
681
681
  stage->xwin_width = 640;
682
682
  stage->xwin_height = 480;
683
 
  stage->xvisinfo = None;
684
683
 
685
684
  stage->wm_state = STAGE_X11_WITHDRAWN;
686
685
 
687
686
  stage->is_foreign_xwin = FALSE;
688
 
  stage->fullscreen_on_map = FALSE;
 
687
  stage->fullscreening = FALSE;
689
688
  stage->is_cursor_visible = TRUE;
 
689
  stage->viewport_initialized = FALSE;
690
690
 
691
691
  stage->title = NULL;
692
692
 
705
705
  iface->set_user_resizable = clutter_stage_x11_set_user_resizable;
706
706
  iface->show = clutter_stage_x11_show;
707
707
  iface->hide = clutter_stage_x11_hide;
 
708
  iface->resize = clutter_stage_x11_resize;
 
709
  iface->get_geometry = clutter_stage_x11_get_geometry;
 
710
  iface->realize = clutter_stage_x11_realize;
708
711
}
709
712
 
710
713
/**
711
714
 * clutter_x11_get_stage_window:
712
715
 * @stage: a #ClutterStage
713
716
 *
714
 
 * Gets the stages X Window. 
 
717
 * Gets the stages X Window.
715
718
 *
716
719
 * Return value: An XID for the stage window.
717
720
 *
769
772
 * clutter_x11_get_stage_visual:
770
773
 * @stage: a #ClutterStage
771
774
 *
772
 
 * Returns the stage XVisualInfo
773
 
 *
774
 
 * Return value: The XVisualInfo for the stage.
 
775
 * Returns an XVisualInfo suitable for creating a foreign window for the given
 
776
 * stage. NOTE: It doesn't do as the name may suggest, which is return the
 
777
 * XVisualInfo that was used to create an existing window for the given stage.
 
778
 *
 
779
 * XXX: It might be best to deprecate this function and replace with something
 
780
 * along the lines of clutter_backend_x11_get_foreign_visual () or perhaps
 
781
 * clutter_stage_x11_get_foreign_visual ()
 
782
 *
 
783
 * Return value: An XVisualInfo suitable for creating a foreign stage. Use
 
784
 *   XFree() to free the returned value instead
 
785
 *
 
786
 * Deprecated: 1.2: Use clutter_x11_get_visual_info() instead
775
787
 *
776
788
 * Since: 0.4
777
789
 */
778
790
XVisualInfo *
779
791
clutter_x11_get_stage_visual (ClutterStage *stage)
780
792
{
781
 
  ClutterStageWindow *impl;
782
 
  ClutterStageX11 *stage_x11;
783
 
  gboolean is_offscreen = FALSE;
784
 
 
785
 
  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
786
 
 
787
 
  g_object_get (G_OBJECT (stage), "offscreen", &is_offscreen, NULL);
788
 
 
789
 
  impl = _clutter_stage_get_window (stage);
790
 
  g_assert (CLUTTER_IS_STAGE_X11 (impl));
791
 
 
792
 
  stage_x11 = CLUTTER_STAGE_X11 (impl);
793
 
 
794
 
  if (stage_x11->xvisinfo == NULL)
795
 
    {
796
 
      ClutterBackendX11 *backend_x11 = stage_x11->backend;
797
 
 
798
 
      stage_x11->xvisinfo =
799
 
        clutter_backend_x11_get_visual_info (backend_x11, is_offscreen);
800
 
    }
801
 
 
802
 
  return stage_x11->xvisinfo;
 
793
  ClutterBackend *backend = clutter_get_default_backend ();
 
794
  ClutterBackendX11 *backend_x11;
 
795
 
 
796
  g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend), NULL);
 
797
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
798
 
 
799
  return clutter_backend_x11_get_visual_info (backend_x11);
803
800
}
804
801
 
805
802
typedef struct {
814
811
                             void         *data)
815
812
{
816
813
  ForeignWindowData *fwd = data;
 
814
  ClutterBackend *backend = clutter_get_default_backend ();
 
815
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
817
816
 
818
817
  CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)",
819
818
                (unsigned int) fwd->xwindow);
822
821
    {
823
822
      CLUTTER_NOTE (BACKEND, "Destroying previous window (0x%x)",
824
823
                    (unsigned int) fwd->xwindow);
825
 
      XDestroyWindow (fwd->stage_x11->xdpy, fwd->stage_x11->xwin);
 
824
      XDestroyWindow (backend_x11->xdpy, fwd->stage_x11->xwin);
826
825
    }
827
826
 
828
827
  fwd->stage_x11->xwin = fwd->xwindow;
855
854
clutter_x11_set_stage_foreign (ClutterStage *stage,
856
855
                               Window        xwindow)
857
856
{
 
857
  ClutterBackend *backend = clutter_get_default_backend ();
 
858
  ClutterBackendX11 *backend_x11;
858
859
  ClutterStageX11 *stage_x11;
859
860
  ClutterStageWindow *impl;
860
861
  ClutterActor *actor;
863
864
  Window root_return;
864
865
  Status status;
865
866
  ForeignWindowData fwd;
 
867
  XVisualInfo *xvisinfo;
 
868
 
 
869
  g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend), FALSE);
 
870
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
866
871
 
867
872
  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
868
873
  g_return_val_if_fail (xwindow != None, FALSE);
872
877
  impl = _clutter_stage_get_window (stage);
873
878
  stage_x11 = CLUTTER_STAGE_X11 (impl);
874
879
 
 
880
  xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
 
881
 
875
882
  clutter_x11_trap_x_errors ();
876
883
 
877
 
  status = XGetGeometry (stage_x11->xdpy, xwindow,
 
884
  status = XGetGeometry (backend_x11->xdpy, xwindow,
878
885
                         &root_return,
879
886
                         &x, &y,
880
887
                         &width, &height,
881
888
                         &border,
882
889
                         &depth);
883
 
  
 
890
 
884
891
  if (clutter_x11_untrap_x_errors () ||
885
892
      !status ||
886
893
      width == 0 || height == 0 ||
887
 
      depth != stage_x11->xvisinfo->depth)
 
894
      depth != xvisinfo->depth)
888
895
    {
889
896
      g_warning ("Unable to retrieve the new window geometry");
890
897
      return FALSE;