Tizen 2.1 release
[platform/core/uifw/e17.git] / src / modules / wl_drm / e_mod_main.c
1 #include "e.h"
2 #include "e_mod_main.h"
3
4 /* local function prototypes */
5 static void _cb_tty(E_Compositor *comp, int event);
6 static int _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__);
7 static int _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data);
8 static void _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data);
9 static void _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data);
10 static Eina_Bool _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev);
11 static void _sprites_init(E_Drm_Compositor *dcomp);
12 static void _sprites_shutdown(E_Drm_Compositor *dcomp);
13 static Eina_Bool _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device);
14 static Eina_Bool _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device);
15 static void _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device);
16 static Eina_Bool _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev);
17
18 /* local variables */
19 static drmModeModeInfo builtin_mode = 
20 {
21    63500,                       /* clock */
22    1024, 1072, 1176, 1328, 0,
23    768, 771, 775, 798, 0,
24    59920,
25    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
26    0,
27    "1024x768"
28 };
29
30 /* external variables */
31 E_Drm_Compositor *_drm_comp = NULL;
32
33 EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Drm" };
34
35 EAPI void *
36 e_modapi_init(E_Module *m)
37 {
38    struct wl_display *disp;
39    struct udev_enumerate *ue;
40    struct udev_list_entry *entry;
41    struct udev_device *drm_dev = NULL;
42    struct wl_event_loop *loop;
43    const char *seat = NULL;
44
45    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
46
47    /* try to get the wayland display */
48    if (!(disp = (struct wl_display *)m->data)) return NULL;
49
50    /* allocate space for the drm compositor */
51    if (!(_drm_comp = malloc(sizeof(E_Drm_Compositor)))) return NULL;
52
53    memset(_drm_comp, 0, sizeof(E_Drm_Compositor));
54
55    if (!(_drm_comp->udev = udev_new())) 
56      {
57         free(_drm_comp);
58         return NULL;
59      }
60
61    _drm_comp->base.display = disp;
62    if (!(_drm_comp->tty = e_tty_create(&_drm_comp->base, _cb_tty, 0)))
63      {
64         free(_drm_comp);
65         return NULL;
66      }
67
68    ue = udev_enumerate_new(_drm_comp->udev);
69    udev_enumerate_add_match_subsystem(ue, "drm");
70    udev_enumerate_add_match_sysname(ue, "card[0-9]*");
71
72    udev_enumerate_scan_devices(ue);
73    udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue))
74      {
75         struct udev_device *dev;
76         const char *path = NULL;
77
78         path = udev_list_entry_get_name(entry);
79         dev = udev_device_new_from_syspath(_drm_comp->udev, path);
80         if (!(seat = udev_device_get_property_value(dev, "ID_SEAT")))
81           seat = "seat0";
82         if (!strcmp(seat, "seat0")) 
83           {
84              drm_dev = dev;
85              break;
86           }
87         udev_device_unref(dev);
88      }
89
90    if (!drm_dev)
91      {
92         free(_drm_comp);
93         return NULL;
94      }
95
96    /* init egl */
97    if (!_egl_init(_drm_comp, drm_dev))
98      {
99         free(_drm_comp);
100         return NULL;
101      }
102
103    /* _drm_comp->base.destroy = _cb_destroy; */
104    _drm_comp->base.focus = EINA_TRUE;
105
106    _drm_comp->prev_state = E_COMPOSITOR_STATE_ACTIVE;
107
108    glGenFramebuffers(1, &_drm_comp->base.fbo);
109    glBindFramebuffer(GL_FRAMEBUFFER, _drm_comp->base.fbo);
110
111    if (!e_compositor_init(&_drm_comp->base, disp))
112      {
113         free(_drm_comp);
114         return NULL;
115      }
116
117    wl_list_init(&_drm_comp->sprites);
118    _sprites_init(_drm_comp);
119
120    if (!_outputs_init(_drm_comp, 0, drm_dev))
121      {
122         free(_drm_comp);
123         return NULL;
124      }
125
126    udev_device_unref(drm_dev);
127    udev_enumerate_unref(ue);
128
129    e_evdev_input_create(&_drm_comp->base, _drm_comp->udev, seat);
130
131    loop = wl_display_get_event_loop(_drm_comp->base.display);
132    _drm_comp->drm_source = 
133      wl_event_loop_add_fd(loop, _drm_comp->drm.fd, WL_EVENT_READABLE, 
134                           _cb_drm_input, _drm_comp);
135
136    _drm_comp->udev_monitor = 
137      udev_monitor_new_from_netlink(_drm_comp->udev, "udev");
138    if (!_drm_comp->udev_monitor)
139      {
140         free(_drm_comp);
141         return NULL;
142      }
143    udev_monitor_filter_add_match_subsystem_devtype(_drm_comp->udev_monitor, 
144                                                    "drm", NULL);
145
146    _drm_comp->udev_drm_source = 
147      wl_event_loop_add_fd(loop, udev_monitor_get_fd(_drm_comp->udev_monitor), 
148                           WL_EVENT_READABLE, _cb_drm_udev_event, _drm_comp);
149    if (udev_monitor_enable_receiving(_drm_comp->udev_monitor) < 0)
150      {
151         free(_drm_comp);
152         return NULL;
153      }
154
155    return &_drm_comp->base;
156 }
157
158 EAPI int 
159 e_modapi_shutdown(E_Module *m __UNUSED__)
160 {
161    E_Input_Device *input, *next;
162
163    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
164
165    e_compositor_shutdown(&_drm_comp->base);
166    gbm_device_destroy(_drm_comp->gbm);
167    _sprites_shutdown(_drm_comp);
168    drmDropMaster(_drm_comp->drm.fd);
169    e_tty_destroy(_drm_comp->tty);
170
171    wl_list_for_each_safe(input, next, &_drm_comp->base.inputs, link)
172      e_evdev_input_destroy(input);
173
174    free(_drm_comp);
175    _drm_comp = NULL;
176
177    return 1;
178 }
179
180 EAPI int 
181 e_modapi_save(E_Module *m __UNUSED__)
182 {
183    return 1;
184 }
185
186 /* local function prototypes */
187 static void 
188 _cb_tty(E_Compositor *comp, int event)
189 {
190    E_Output *output;
191    E_Drm_Output *doutput;
192    E_Sprite *sprite;
193    E_Input_Device *input;
194
195    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
196
197    switch (event)
198      {
199       case 0: // TTY_ENTER_VT
200         comp->focus = EINA_TRUE;
201         if (drmSetMaster(_drm_comp->drm.fd))
202           {
203              printf("Failed to set master: %m\n");
204              wl_display_terminate(comp->display);
205           }
206         comp->state = _drm_comp->prev_state;
207         e_drm_output_set_modes(_drm_comp);
208         e_compositor_damage_all(comp);
209         wl_list_for_each(input, &comp->inputs, link)
210           e_evdev_add_devices(_drm_comp->udev, input);
211         break;
212       case 1: // TTY_LEAVE_VT
213         comp->focus = EINA_FALSE;
214         _drm_comp->prev_state = comp->state;
215         comp->state = E_COMPOSITOR_STATE_SLEEPING;
216         wl_list_for_each(output, &comp->outputs, link)
217           {
218              output->repaint_needed = EINA_FALSE;
219              e_drm_output_set_cursor(output, NULL);
220           }
221         doutput = 
222           container_of(comp->outputs.next, E_Drm_Output, base.link);
223
224         wl_list_for_each(sprite, &_drm_comp->sprites, link)
225           drmModeSetPlane(_drm_comp->drm.fd, sprite->plane_id, 
226                           doutput->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
227
228         wl_list_for_each(input, &comp->inputs, link)
229           e_evdev_remove_devices(input);
230
231         if (drmDropMaster(_drm_comp->drm.fd < 0))
232           printf("Failed to drop master: %m\n");
233
234         break;
235      }
236 }
237
238 static int 
239 _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__)
240 {
241    drmEventContext ectxt;
242
243    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
244
245    memset(&ectxt, 0, sizeof(ectxt));
246
247    ectxt.version = DRM_EVENT_CONTEXT_VERSION;
248    ectxt.page_flip_handler = _cb_drm_page_flip;
249    ectxt.vblank_handler = _cb_drm_vblank;
250    drmHandleEvent(fd, &ectxt);
251
252    return 1;
253 }
254
255 static int 
256 _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data)
257 {
258    E_Drm_Compositor *dcomp;
259    struct udev_device *event;
260
261    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
262
263    if (!(dcomp = data)) return 1;
264    event = udev_monitor_receive_device(dcomp->udev_monitor);
265    if (_udev_event_is_hotplug(dcomp, event))
266      _outputs_update(dcomp, event);
267    udev_device_unref(event);
268    return 1;
269 }
270
271 static void 
272 _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data)
273 {
274    E_Drm_Output *doutput;
275    E_Drm_Compositor *dcomp;
276    unsigned int msecs;
277
278    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
279
280    if (!(doutput = data)) return;
281    dcomp = (E_Drm_Compositor *)doutput->base.compositor;
282
283    if (doutput->scanout_buffer)
284      {
285         e_buffer_post_release(doutput->scanout_buffer);
286         wl_list_remove(&doutput->scanout_buffer_destroy_listener.link);
287         doutput->scanout_buffer = NULL;
288         drmModeRmFB(dcomp->drm.fd, doutput->fs_surf_fb_id);
289         doutput->fs_surf_fb_id = 0;
290      }
291
292    if (doutput->pending_scanout_buffer)
293      {
294         doutput->scanout_buffer = doutput->pending_scanout_buffer;
295         wl_list_remove(&doutput->pending_scanout_buffer_destroy_listener.link);
296         wl_signal_add(&doutput->scanout_buffer->resource.destroy_signal,
297                        &doutput->scanout_buffer_destroy_listener);
298         doutput->pending_scanout_buffer = NULL;
299         doutput->fs_surf_fb_id = doutput->pending_fs_surf_fb_id;
300         doutput->pending_fs_surf_fb_id = 0;
301      }
302
303    msecs = sec * 1000 + usec / 1000;
304    e_output_finish_frame(&doutput->base, msecs);
305 }
306
307 static void 
308 _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data)
309 {
310    E_Sprite *es;
311    E_Drm_Compositor *dcomp;
312
313    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
314
315    if (!(es = data)) return;
316    dcomp = es->compositor;
317
318    if (es->surface)
319      {
320         e_buffer_post_release(es->surface->buffer);
321         wl_list_remove(&es->destroy_listener.link);
322         es->surface = NULL;
323         drmModeRmFB(dcomp->drm.fd, es->fb_id);
324         es->fb_id = 0;
325      }
326
327    if (es->pending_surface)
328      {
329         wl_list_remove(&es->pending_destroy_listener.link);
330         wl_signal_add(&es->pending_surface->buffer->resource.destroy_signal,
331                        &es->destroy_listener);
332         es->surface = es->pending_surface;
333         es->pending_surface = NULL;
334         es->fb_id = es->pending_fb_id;
335         es->pending_fb_id = 0;
336      }
337 }
338
339 static Eina_Bool 
340 _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev)
341 {
342    EGLint maj, min;
343    const char *ext, *fname, *snum;
344    int fd = 0;
345    static const EGLint ctxt_att[] = 
346      {
347         EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
348      };
349
350    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
351
352    if ((snum = udev_device_get_sysnum(dev)))
353      dcomp->drm.id = atoi(snum);
354    if ((!snum) || (dcomp->drm.id < 0)) 
355      return EINA_FALSE;
356
357    fname = udev_device_get_devnode(dev);
358    if (!(fd = open(fname, (O_RDWR | O_CLOEXEC))))
359      return EINA_FALSE;
360
361    dcomp->drm.fd = fd;
362    dcomp->gbm = gbm_create_device(dcomp->drm.fd);
363
364 //   dcomp->base.egl_display = eglGetDisplay(dcomp->base.display);
365    dcomp->base.egl_display = eglGetDisplay(dcomp->gbm);
366    if (!dcomp->base.egl_display)
367      return EINA_FALSE;
368
369    if (!eglInitialize(dcomp->base.egl_display, &maj, &min))
370      return EINA_FALSE;
371
372    ext = eglQueryString(dcomp->base.egl_display, EGL_EXTENSIONS);
373    if (!strstr(ext, "EGL_KHR_surfaceless_gles2"))
374      return EINA_FALSE;
375
376    if (!eglBindAPI(EGL_OPENGL_ES_API)) return EINA_FALSE;
377
378    dcomp->base.egl_context = 
379      eglCreateContext(dcomp->base.egl_display, NULL, EGL_NO_CONTEXT, ctxt_att);
380    if (!dcomp->base.egl_context) return EINA_FALSE;
381
382    if (!eglMakeCurrent(dcomp->base.egl_display, EGL_NO_SURFACE, 
383                        EGL_NO_SURFACE, dcomp->base.egl_context))
384      return EINA_FALSE;
385
386    return EINA_TRUE;
387 }
388
389 static void 
390 _sprites_init(E_Drm_Compositor *dcomp)
391 {
392    E_Sprite *es;
393    drmModePlaneRes *res;
394    drmModePlane *plane;
395    unsigned int i = 0;
396
397    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
398
399    if (!(res = drmModeGetPlaneResources(dcomp->drm.fd)))
400      return;
401
402    for (i = 0; i < res->count_planes; i++)
403      {
404         if (!(plane = drmModeGetPlane(dcomp->drm.fd, res->planes[i])))
405           continue;
406         if (!(es = e_sprite_create(dcomp, plane))) 
407           {
408              free(plane);
409              continue;
410           }
411         drmModeFreePlane(plane);
412         wl_list_insert(&dcomp->sprites, &es->link);
413      }
414    free(res->planes);
415    free(res);
416 }
417
418 static void 
419 _sprites_shutdown(E_Drm_Compositor *dcomp)
420 {
421    E_Drm_Output *doutput;
422    E_Sprite *es, *next;
423
424    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
425
426    doutput = container_of(dcomp->base.outputs.next, E_Drm_Output, base.link);
427
428    wl_list_for_each_safe(es, next, &dcomp->sprites, link)
429      {
430         drmModeSetPlane(dcomp->drm.fd, es->plane_id, doutput->crtc_id, 
431                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
432         drmModeRmFB(dcomp->drm.fd, es->fb_id);
433         free(es);
434      }
435 }
436
437 static Eina_Bool 
438 _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device)
439 {
440    drmModeConnector *connector;
441    drmModeRes *res;
442    int i = 0, x = 0, y = 0;
443
444    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
445
446    if (!(res = drmModeGetResources(dcomp->drm.fd)))
447      return EINA_FALSE;
448
449    if (!(dcomp->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
450      {
451         drmModeFreeResources(res);
452         return EINA_FALSE;
453      }
454
455    dcomp->num_crtcs = res->count_crtcs;
456    memcpy(dcomp->crtcs, res->crtcs, sizeof(unsigned int) * dcomp->num_crtcs);
457
458    for (i = 0; i < res->count_connectors; i++)
459      {
460         if (!(connector = 
461               drmModeGetConnector(dcomp->drm.fd, res->connectors[i])))
462           continue;
463         if ((connector->connection == DRM_MODE_CONNECTED) && 
464             ((conn == 0) || (connector->connector_id == conn)))
465           {
466              if (!_output_create(dcomp, res, connector, x, y, drm_device))
467                {
468                   drmModeFreeConnector(connector);
469                   continue;
470                }
471              x += container_of(dcomp->base.outputs.prev, E_Output, 
472                                link)->current->w;
473           }
474         drmModeFreeConnector(connector);
475      }
476
477    if (wl_list_empty(&dcomp->base.outputs))
478      {
479         drmModeFreeResources(res);
480         return EINA_FALSE;
481      }
482
483    drmModeFreeResources(res);
484
485    return EINA_TRUE;
486 }
487
488 static Eina_Bool 
489 _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device)
490 {
491    E_Drm_Output *output;
492    E_Drm_Output_Mode *mode, *next;
493    drmModeEncoder *encoder;
494    int i = 0, ret = 0;
495    unsigned int hdl, stride;
496
497    if (!(encoder = drmModeGetEncoder(dcomp->drm.fd, conn->encoders[0])))
498      return EINA_FALSE;
499
500    for (i = 0; i < res->count_crtcs; i++)
501      {
502         if ((encoder->possible_crtcs & (1 << i)) && 
503             !(dcomp->crtc_alloc & (1 << res->crtcs[i])))
504           break;
505      }
506    if (i == res->count_crtcs)
507      {
508         drmModeFreeEncoder(encoder);
509         return EINA_FALSE;
510      }
511
512    if (!(output = malloc(sizeof(E_Drm_Output))))
513      {
514         drmModeFreeEncoder(encoder);
515         return EINA_FALSE;
516      }
517
518    memset(output, 0, sizeof(E_Drm_Output));
519
520    output->fb_id[0] = -1;
521    output->fb_id[1] = -1;
522    output->base.subpixel = e_drm_output_subpixel_convert(conn->subpixel);
523    output->base.make = "unknown";
524    output->base.model = "unknown";
525    wl_list_init(&output->base.modes);
526
527    output->crtc_id = res->crtcs[i];
528    dcomp->crtc_alloc |= (1 << output->crtc_id);
529    output->conn_id = conn->connector_id;
530    dcomp->conn_alloc |= (1 << output->conn_id);
531
532    output->orig_crtc = drmModeGetCrtc(dcomp->drm.fd, output->crtc_id);
533    drmModeFreeEncoder(encoder);
534
535    for (i = 0; i < conn->count_modes; i++)
536      {
537         if (!e_drm_output_add_mode(output, &conn->modes[i]))
538           goto efree;
539      }
540
541    if (conn->count_modes == 0)
542      {
543         if (!e_drm_output_add_mode(output, &builtin_mode))
544           goto efree;
545      }
546
547    mode = container_of(output->base.modes.next, E_Drm_Output_Mode, base.link);
548    output->base.current = &mode->base;
549    mode->base.flags = (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED);
550
551    glGenRenderbuffers(2, output->rbo);
552
553    for (i = 0; i < 2; i++)
554      {
555         glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
556         output->bo[i] = 
557           gbm_bo_create(dcomp->gbm, output->base.current->w, 
558                         output->base.current->h, GBM_BO_FORMAT_XRGB8888, 
559                         (GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
560         if (!output->bo[i]) goto ebuffs;
561         output->image[i] = 
562           dcomp->base.create_image(dcomp->base.egl_display, NULL, 
563                                    EGL_NATIVE_PIXMAP_KHR, output->bo[i], NULL);
564         if (!output->image[i]) goto ebuffs;
565         dcomp->base.image_target_renderbuffer_storage(GL_RENDERBUFFER, 
566                                                       output->image[i]);
567         stride = gbm_bo_get_pitch(output->bo[i]);
568         hdl = gbm_bo_get_handle(output->bo[i]).u32;
569         ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w, 
570                            output->base.current->h, 24, 32, stride, hdl, 
571                            &output->fb_id[i]);
572         if (ret) goto ebuffs;
573      }
574
575    output->current = 0;
576    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
577                              GL_RENDERBUFFER, output->rbo[output->current]);
578    ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id, 
579                         output->fb_id[output->current ^ 1], 0, 0, 
580                         &output->conn_id, 1, &mode->info);
581    if (ret) goto efb;
582
583    /* TODO: backlight init */
584
585    e_output_init(&output->base, &dcomp->base, x, y, 
586                  conn->mmWidth, conn->mmHeight, 0);
587
588    wl_list_insert(dcomp->base.outputs.prev, &output->base.link);
589
590    output->scanout_buffer_destroy_listener.notify = 
591      e_drm_output_scanout_buffer_destroy;
592    output->pending_scanout_buffer_destroy_listener.notify = 
593      e_drm_output_pending_scanout_buffer_destroy;
594
595    output->pending_fs_surf_fb_id = 0;
596    output->base.repaint = e_drm_output_repaint;
597    output->base.destroy = e_drm_output_destroy;
598    output->base.assign_planes = e_drm_output_assign_planes;
599    output->base.set_dpms = e_drm_output_set_dpms;
600
601    return EINA_TRUE;
602
603 efb:
604    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
605                              GL_RENDERBUFFER, 0);
606
607 ebuffs:
608    for (i = 0; i < 2; i++)
609      {
610         if ((int)output->fb_id[i] != -1)
611           drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
612         if (output->image[i])
613           dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
614         if (output->bo[i]) gbm_bo_destroy(output->bo[i]);
615      }
616    glBindRenderbuffer(GL_RENDERBUFFER, 0);
617    glDeleteRenderbuffers(2, output->rbo);
618
619 efree:
620    wl_list_for_each_safe(mode, next, &output->base.modes, base.link)
621      {
622         wl_list_remove(&mode->base.link);
623         free(mode);
624      }
625    drmModeFreeCrtc(output->orig_crtc);
626    dcomp->crtc_alloc &= ~(1 << output->crtc_id);
627    dcomp->conn_alloc &= ~(1 << output->conn_id);
628    free(output);
629
630    return EINA_TRUE;
631 }
632
633 static void 
634 _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device)
635 {
636    drmModeConnector *conn;
637    drmModeRes *res;
638    E_Drm_Output *doutput, *next;
639    int x = 0, y = 0;
640    int xo = 0, yo = 0;
641    unsigned int connected = 0, disconnects = 0;
642    int i = 0;
643
644    if (!(res = drmModeGetResources(dcomp->drm.fd)))
645      return;
646
647    for (i = 0; i < res->count_connectors; i++)
648      {
649         int conn_id;
650
651         conn_id = res->connectors[i];
652         if (!(conn = drmModeGetConnector(dcomp->drm.fd, conn_id)))
653           continue;
654         if (conn->connection != DRM_MODE_CONNECTED)
655           {
656              drmModeFreeConnector(conn);
657              continue;
658           }
659         connected |= (1 << conn_id);
660         if (!(dcomp->conn_alloc & (1 << conn_id)))
661           {
662              E_Output *last;
663
664              last = container_of(dcomp->base.outputs.prev, E_Output, link);
665              if (!wl_list_empty(&dcomp->base.outputs))
666                x = last->x + last->current->w;
667              else
668                x = 0;
669              y = 0;
670              _output_create(dcomp, res, conn, x, y, drm_device);
671           }
672         drmModeFreeConnector(conn);
673      }
674    drmModeFreeResources(res);
675
676    if ((disconnects = dcomp->conn_alloc & ~connected))
677      {
678         wl_list_for_each_safe(doutput, next, &dcomp->base.outputs, base.link)
679           {
680              if ((xo != 0) || (yo != 0))
681                e_output_move(&doutput->base, doutput->base.x - xo, 
682                              doutput->base.y - yo);
683              if (disconnects & (1 << doutput->conn_id))
684                {
685                   disconnects &= ~(1 << doutput->conn_id);
686                   xo += doutput->base.current->w;
687                   e_drm_output_destroy(&doutput->base);
688                }
689           }
690      }
691
692    if (dcomp->conn_alloc == 0)
693      wl_display_terminate(dcomp->base.display);
694 }
695
696 static Eina_Bool 
697 _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev)
698 {
699    const char *snum, *val;
700
701    DLOGFN(__FILE__, __LINE__, __FUNCTION__);
702
703    snum = udev_device_get_sysnum(dev);
704    if ((!snum) || (atoi(snum) != dcomp->drm.id)) 
705      return EINA_FALSE;
706
707    if (!(val = udev_device_get_property_value(dev, "HOTPLUG")))
708      return EINA_FALSE;
709
710    if (!strcmp(val, "1")) return EINA_TRUE;
711
712    return EINA_FALSE;
713 }